Ethereal-dev: Re: [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: Mon, 28 Mar 2005 15:13:33 +0200
Hi list,
please have a closer look at this patch to packet-bacapp.c.
I have added packet-bacapp.h with descriptions conforming to doxygen too. It will be used by packet-bacapp.c.

Check in if possible.

best regards
Herbert Lischka

Guy Harris wrote:

Checked in.


...and backed out, because its heavy use of recursion instead of iteration means that malformed packets can cause it to overflow the process's stack and crash.
done and added some checks to avoid endless loops on malformed packages

Please fix that, and also:

    1) fix the problems noted in Ronnie Sahlberg's and my mail messages;
done

2) don't use "match_strval()" to convert numerical values to strings, use "val_to_str()", as a malformed packet could mean that there is no string corresponding to the value;
done

3) don't just cast length values to "guint8" if they might be larger than 8 bits;
done

4) make the length field in the tag/class/LTV value 32 bits, as the BACnet spec I have seems to say it can't be larger than 2^32-1 - and make the tag parsing code handle the "length is > 65535" case;
done

5) don't use "//" comments - not all compilers Ethereal is built with support them;
done

    6) make all routines not used outside packet-bacapp.c static.
done

You might want to consider modeling the BACnet application layer dissector after the packet-ber.c dissector and dissectors using it, e.g. with SEQUENCE, SEQUENCE OF, and CHOICE values dissected with a table handed to a generic SEQUENCE, SEQUENCE OF, or CHOICE dissector.
Sorry, but please have a closer look at chapter 20. ENCODING BACnet
PROTOCOL DATA UNITS.
I found a lot of "-- only if....." in chapter 21. FORMAL DESCRIPTION OF
APPLICATION PROTOCOL DATA UNITS and that's not really helpful...

_______________________________________________
Ethereal-dev mailing list
Ethereal-dev@xxxxxxxxxxxx
http://www.ethereal.com/mailman/listinfo/ethereal-dev





/* packet-bacapp.h
 * Routines for BACnet (APDU) dissection
 * Copyright 2004, Herbert Lischka <lischka@xxxxxxxxxxxxxxxx>, Berlin
 *
 * $Id: packet-bacapp.h,v 1.00 2004/03/11 17:50:07 Lka Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * Copied from README.developer,v 1.23
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef __BACAPP_H__
#define __BACAPP_H__

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <glib.h>

#include <epan/packet.h>

#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif

#ifndef max
#define max(a,b) (((a)>(b))?(a):(b))
#endif

#ifndef FAULT
#define FAULT 			proto_tree_add_text(subtree, tvb, offset, tvb_length(tvb) - offset, "something is going wrong here !!"); \
			offset = tvb_length(tvb);
#endif

#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif

#ifndef LABEL
#define LABEL(lbl) (lbl==NULL ? (guint8 *) "Value: " : lbl)
#endif

/**
 * dissect_bacapp ::= CHOICE {
 *  confirmed-request-PDU       [0] BACnet-Confirmed-Request-PDU,
 *  unconfirmed-request-PDU     [1] BACnet-Unconfirmed-Request-PDU,
 *  simpleACK-PDU               [2] BACnet-SimpleACK-PDU,
 *  complexACK-PDU              [3] BACnet-ComplexACK-PDU,
 *  segmentACK-PDU              [4] BACnet-SegmentACK-PDU,
 *  error-PDU                   [5] BACnet-Error-PDU,
 *  reject-PDU                  [6] BACnet-Reject-PDU,
 *  abort-PDU                   [7] BACnet-Abort-PDU
 * }
 * @param tvb
 * @param pinfo
 * @param tree
 */
void
dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);

/**
 * ConfirmedRequest-PDU ::= SEQUENCE {
 * 	pdu-type					[0] Unsigned (0..15), -- 0 for this PDU Type
 *  segmentedMessage			[1] BOOLEAN,
 *  moreFollows					[2] BOOLEAN,
 *  segmented-response-accepted	[3] BOOLEAN,
 *  reserved					[4] Unsigned (0..3), -- must be set zero
 *  max-segments-accepted		[5] Unsigned (0..7), -- as per 20.1.2.4
 *  max-APDU-length-accepted	[5] Unsigned (0..15), -- as per 20.1.2.5
 *  invokeID					[6] Unsigned (0..255),
 *  sequence-number				[7] Unsigned (0..255) OPTIONAL, -- only if segmented msg
 *  proposed-window-size		[8] Unsigned (0..127) OPTIONAL, -- only if segmented msg
 *  service-choice				[9] BACnetConfirmedServiceChoice,
 *  service-request				[10] BACnet-Confirmed-Service-Request OPTIONAL
 * }
 * @param tvb
 * @param pinfo
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fConfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);

/**
 * Unconfirmed-Request-PDU ::= SEQUENCE {
 * 	pdu-type		[0] Unsigned (0..15), -- 1 for this PDU type
 *  reserved		[1] Unsigned (0..15), -- must be set zero
 *  service-choice	[2] BACnetUnconfirmedServiceChoice,
 *  service-request	[3] BACnetUnconfirmedServiceRequest -- Context-specific tags 0..3 are NOT used in header encoding
 * }
 * @param tvb
 * @param pinfo
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fUnconfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);

/**
 * SimpleACK-PDU ::= SEQUENCE {
 * 	pdu-type		[0] Unsigned (0..15), -- 2 for this PDU type
 *  reserved		[1] Unsigned (0..15), -- must be set zero
 *  invokeID		[2] Unsigned (0..255),
 *  service-ACK-choice	[3] BACnetUnconfirmedServiceChoice -- Context-specific tags 0..3 are NOT used in header encoding
 * }
 * @param tvb
 * @param pinfo
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fSimpleAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);

/**
 * ComplexACK-PDU ::= SEQUENCE {
 * 	pdu-type				[0] Unsigned (0..15), -- 3 for this PDU Type
 *  segmentedMessage		[1] BOOLEAN,
 *  moreFollows				[2] BOOLEAN,
 *  reserved				[3] Unsigned (0..3), -- must be set zero
 *  invokeID				[4] Unsigned (0..255),
 *  sequence-number			[5] Unsigned (0..255) OPTIONAL, -- only if segmented msg
 *  proposed-window-size	[6] Unsigned (0..127) OPTIONAL, -- only if segmented msg
 *  service-ACK-choice 		[7] BACnetConfirmedServiceChoice,
 *  service-ACK				[8] BACnet-Confirmed-Service-Request  -- Context-specific tags 0..8 are NOT used in header encoding
 * }
 * @param tvb
 * @param pinfo
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fComplexAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);

/**
 * SegmentACK-PDU ::= SEQUENCE {
 * 	pdu-type				[0] Unsigned (0..15), -- 4 for this PDU Type
 *  reserved				[1] Unsigned (0..3), -- must be set zero
 *  negative-ACK			[2] BOOLEAN,
 *  server					[3] BOOLEAN,
 *  original-invokeID		[4] Unsigned (0..255),
 *  sequence-number			[5] Unsigned (0..255),
 *  actual-window-size		[6] Unsigned (0..127)
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fSegmentAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * Error-PDU ::= SEQUENCE {
 * 	pdu-type				[0] Unsigned (0..15), -- 5 for this PDU Type
 *  reserved				[1] Unsigned (0..3), -- must be set zero
 *  original-invokeID		[2] Unsigned (0..255),
 *  error-choice			[3] BACnetConfirmedServiceChoice,
 *  error					[4] BACnet-Error
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fErrorPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * Reject-PDU ::= SEQUENCE {
 * 	pdu-type				[0] Unsigned (0..15), -- 6 for this PDU Type
 *  reserved				[1] Unsigned (0..3), -- must be set zero
 *  original-invokeID		[2] Unsigned (0..255),
 *  reject-reason			[3] BACnetRejectReason
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fRejectPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * Abort-PDU ::= SEQUENCE {
 * 	pdu-type				[0] Unsigned (0..15), -- 7 for this PDU Type
 *  reserved				[1] Unsigned (0..3), -- must be set zero
 *  server					[2] BOOLEAN,
 *  original-invokeID		[3] Unsigned (0..255),
 *  abort-reason			[4] BACnetAbortReason
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fAbortPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * 20.2.4, adds the label with max 64Bit unsigned Integer Value to tree
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param label 
 * @return modified offset
 */
static guint
fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);

/**
 * 20.2.5, adds the label with max 64Bit signed Integer Value to tree
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param label 
 * @return modified offset
 */
static guint
fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);

/**
 * 20.2.8, adds the label with Octet String to tree; if lvt == 0 then lvt = restOfFrame
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param label 
 * @param lvt length of String
 * @return modified offset
 */
static guint
fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, guint32 lvt);

/**
 * 20.2.12, adds the label with Date Value to tree
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param label 
 * @return modified offset
 */
static guint
fDate    (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);

/**
 * 20.2.13, adds the label with Time Value to tree
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param label 
 * @return modified offset
 */
static guint
fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);

/**
 * 20.2.14, adds Object Identifier to tree
 * use BIG ENDIAN: Bits 31..22 Object Type, Bits 21..0 Instance Number
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnet-Confirmed-Service-Request ::= CHOICE {
 * }
 * @param tvb
 * @param tree
 * @param offset
 * @param service_choice
 * @return offset
 */
static guint
fConfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice);

/**
 * BACnet-Confirmed-Service-ACK ::= CHOICE {
 * }
 * @param tvb
 * @param tree
 * @param offset
 * @param service_choice
 * @return offset
 */
static guint
fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice);

/**
 * AcknowledgeAlarm-Request ::= SEQUENCE {
 * 	acknowledgingProcessIdentifier	[0]	Unsigned32,
 * 	eventObjectIdentifier	[1] BACnetObjectIdentifer,
 * 	eventStateAcknowledge	[2] BACnetEventState,
 * 	timeStamp	[3] BACnetTimeStamp,
 * 	acknowledgementSource	[4] Character String,
 *  timeOfAcknowledgement	[5] BACnetTimeStamp
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fAcknowlegdeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ConfirmedCOVNotification-Request ::= SEQUENCE {
 * 	subscriberProcessIdentifier	[0]	Unsigned32,
 * 	initiatingDeviceIdentifier	[1] BACnetObjectIdentifer,
 * 	monitoredObjectIdentifier	[2] BACnetObjectIdentifer,
 * 	timeRemaining	[3] unsigned,
 * 	listOfValues	[4] SEQUENCE OF BACnetPropertyValues
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ConfirmedEventNotification-Request ::= SEQUENCE {
 * 	ProcessIdentifier	[0]	Unsigned32,
 * 	initiatingDeviceIdentifier	[1] BACnetObjectIdentifer,
 * 	eventObjectIdentifier	[2] BACnetObjectIdentifer,
 * 	timeStamp	[3] BACnetTimeStamp,
 * 	notificationClass	[4] unsigned,
 * 	priority	[5] unsigned8,
 * 	eventType	[6] BACnetEventType,
 * 	messageText	[7] CharacterString OPTIONAL,
 * 	notifyType	[8] BACnetNotifyType,
 * 	ackRequired	[9] BOOLEAN OPTIONAL,
 * 	fromState	[10] BACnetEventState OPTIONAL,
 * 	toState	[11] BACnetEventState,
 * 	eventValues	[12] BACnetNotificationParameters OPTIONAL
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * GetAlarmSummary-ACK ::= SEQUENCE OF SEQUENCE {
 * 	objectIdentifier	BACnetObjectIdentifer,
 * 	alarmState	BACnetEventState,
 * 	acknowledgedTransitions	 BACnetEventTransitionBits
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fGetAlarmSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * GetEnrollmentSummary-Request ::= SEQUENCE {
 * 	acknowledgmentFilter	[0]	ENUMERATED {
 *      all (0),
 *      acked   (1),
 *      not-acked   (2)
 *      },
 * 	enrollmentFilter	[1] BACnetRecipientProcess OPTIONAL,
 * 	eventStateFilter	[2] ENUMERATED {
 *      offnormal   (0),
 *      fault   (1),
 *      normal  (2),
 *      all (3),
 *      active  (4)
 *      },
 * 	eventTypeFilter	[3] BACnetEventType OPTIONAL,
 * 	priorityFilter	[4] SEQUENCE {
 *      minPriority [0] Unsigned8,
 *      maxPriority [1] Unsigned8
 *      } OPTIONAL,
 *  notificationClassFilter	[5] Unsigned OPTIONAL
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fGetEnrollmentSummaryRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * GetEnrollmentSummary-ACK ::= SEQUENCE OF SEQUENCE {
 * 	objectIdentifier	BACnetObjectIdentifer,
 * 	eventType	BACnetEventType,
 * 	eventState	BACnetEventState,
 * 	priority    Unsigned8,
 *  notificationClass   Unsigned OPTIONAL
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fGetEnrollmentSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * GetEventInformation-Request ::= SEQUENCE {
 * 	lastReceivedObjectIdentifier	[0] BACnetObjectIdentifer
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fGetEventInformationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * GetEventInformation-ACK ::= SEQUENCE {
 * 	listOfEventSummaries	[0] listOfEventSummaries,
 *  moreEvents  [1] BOOLEAN
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fGetEventInformationACK (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * LifeSafetyOperation-Request ::= SEQUENCE {
 * 	requestingProcessIdentifier	[0]	Unsigned32
 * 	requestingSource	[1] CharacterString
 * 	request	[2] BACnetLifeSafetyOperation
 * 	objectIdentifier	[3] BACnetObjectIdentifier OPTIONAL
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);

/**
 * SubscribeCOV-Request ::= SEQUENCE {
 * 	subscriberProcessIdentifier	[0]	Unsigned32
 * 	monitoredObjectIdentifier	[1] BACnetObjectIdentifier
 * 	issueConfirmedNotifications	[2] BOOLEAN OPTIONAL
 * 	lifetime	[3] Unsigned OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param label 
 * @param src
 * @return modified offset
 */
static guint
fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * SubscribeCOVProperty-Request ::= SEQUENCE {
 * 	subscriberProcessIdentifier	[0]	Unsigned32
 * 	monitoredObjectIdentifier	[1] BACnetObjectIdentifier
 * 	issueConfirmedNotifications	[2] BOOLEAN OPTIONAL
 * 	lifetime	[3] Unsigned OPTIONAL
 * 	monitoredPropertyIdentifier	[4] BACnetPropertyReference OPTIONAL
 * 	covIncrement	[5] Unsigned OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * AtomicReadFile-Request ::= SEQUENCE {
 * 	fileIdentifier	BACnetObjectIdentifier,
 *  accessMethod	CHOICE {
 *  	streamAccess	[0] SEQUENCE {
 *  		fileStartPosition	INTEGER,
 * 			requestedOctetCount	Unsigned
 * 			},
 * 		recordAccess	[1] SEQUENCE {
 * 			fileStartRecord	INTEGER,
 * 			requestedRecordCount	Unsigned
 * 			}
 * 		}
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fAtomicReadFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * AtomicWriteFile-ACK ::= SEQUENCE {
 * 	endOfFile	BOOLEAN,
 *  accessMethod	CHOICE {
 *  	streamAccess	[0] SEQUENCE {
 *  		fileStartPosition	INTEGER,
 * 			fileData	OCTET STRING
 * 			},
 * 		recordAccess	[1] SEQUENCE {
 * 			fileStartRecord	INTEGER,
 * 			returnedRecordCount	Unsigned,
 * 			fileRecordData	SEQUENCE OF OCTET STRING
 * 			}
 * 		}
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fAtomicReadFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * AtomicWriteFile-Request ::= SEQUENCE {
 * 	fileIdentifier	BACnetObjectIdentifier,
 *  accessMethod	CHOICE {
 *  	streamAccess	[0] SEQUENCE {
 *  		fileStartPosition	INTEGER,
 * 			fileData	OCTET STRING
 * 			},
 * 		recordAccess	[1] SEQUENCE {
 * 			fileStartRecord	INTEGER,
 * 			recordCount	Unsigned,
 * 			fileRecordData	SEQUENCE OF OCTET STRING
 * 			}
 * 		}
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * AtomicWriteFile-ACK ::= SEQUENCE {
 * 		fileStartPosition	[0] INTEGER,
 * 	   	fileStartRecord	[1] INTEGER,
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * AddListElement-Request ::= SEQUENCE {
 * 	objectIdentifier	[0] BACnetObjectIdentifier,
 *  propertyIdentifier  [1] BACnetPropertyIdentifier,
 *  propertyArrayIndex  [2] Unsigned OPTIONAL, -- used only with array datatype
 *  listOfElements  [3] ABSTRACT-SYNTAX.&Type
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fAddListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * CreateObject-Request ::= SEQUENCE {
 * 	objectSpecifier	[0] ObjectSpecifier,
 *  listOfInitialValues	[1] SEQUENCE OF BACnetPropertyValue OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fCreateObjectRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset);

/**
 * CreateObject-Request ::= BACnetObjectIdentifier
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * DeleteObject-Request ::= SEQUENCE {
 * 	ObjectIdentifier	BACnetObjectIdentifer
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fDeleteObjectRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReadProperty-Request ::= SEQUENCE {
 * 	objectIdentifier	[0]	BACnetObjectIdentifier,
 * 	propertyIdentifier	[1] BACnetPropertyIdentifier,
 * 	propertyArrayIndex	[2] Unsigned OPTIONAL, -- used only with array datatype
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fReadPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReadProperty-ACK ::= SEQUENCE {
 * 	objectIdentifier	[0]	BACnetObjectIdentifier,
 * 	propertyIdentifier	[1] BACnetPropertyIdentifier,
 * 	propertyArrayIndex	[2] Unsigned OPTIONAL, -- used only with array datatype
 * 	propertyValue	[3] ABSTRACT-SYNTAX.&Type
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fReadPropertyAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReadPropertyConditional-Request ::= SEQUENCE {
 * 	objectSelectionCriteria	[0] objectSelectionCriteria,
 * 	listOfPropertyReferences	[1] SEQUENCE OF BACnetPropertyReference OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fReadPropertyConditionalRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset);

/**
 * ReadPropertyConditional-ACK ::= SEQUENCE {
 * 	listOfPReadAccessResults	SEQUENCE OF ReadAccessResult OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fReadPropertyConditionalAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReadPropertyMultiple-Request ::= SEQUENCE {
 *  listOfReadAccessSpecs	SEQUENCE OF ReadAccessSpecification
 * }
 * @param tvb
 * @param tree
 * @param offset
 * @return offset modified
 */
static guint
fReadPropertyMultipleRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset);

/**
 * ReadPropertyMultiple-Ack ::= SEQUENCE {
 *  listOfReadAccessResults	SEQUENCE OF ReadAccessResult
 * }
 * @param tvb
 * @param tree
 * @param offset
 * @return offset modified
 */
static guint
fReadPropertyMultipleAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReadRange-Request ::= SEQUENCE {
 * 	objectIdentifier	[0] BACnetObjectIdentifier,
 *  propertyIdentifier	[1] BACnetPropertyIdentifier,
 *  propertyArrayIndex	[2] Unsigned OPTIONAL, -- used only with array datatype
 *  	range	CHOICE {
 * 		byPosition	[3] SEQUENCE {
 * 			referencedIndex Unsigned,
 * 			count INTEGER
 * 			},
 * 		byTime	[4] SEQUENCE {
 * 			referenceTime BACnetDateTime,
 * 			count INTEGER
 * 			},
 * 		timeRange	[5] SEQUENCE {
 * 			beginningTime BACnetDateTime,
 * 			endingTime BACnetDateTime
 * 			},
 * 		} OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fReadRangeRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReadRange-ACK ::= SEQUENCE {
 * 	objectIdentifier	[0] BACnetObjectIdentifier,
 *  propertyIdentifier	[1] BACnetPropertyIdentifier,
 *  propertyArrayIndex	[2] Unsigned OPTIONAL, -- used only with array datatype
 *  resultFlags	[3] BACnetResultFlags,
 *  itemCount	[4] Unsigned,
 *  itemData	[5] SEQUENCE OF ABSTRACT-SYNTAX.&Type
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fReadRangeAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * RemoveListElement-Request ::= SEQUENCE {
 * 	objectIdentifier	[0]	BACnetObjectIdentifier,
 * 	propertyIdentifier	[1] BACnetPropertyIdentifier,
 * 	propertyArrayIndex	[2] Unsigned OPTIONAL, -- used only with array datatype
 * 	listOfElements	[3] ABSTRACT-SYNTAX.&Type
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fRemoveListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * WriteProperty-Request ::= SEQUENCE {
 * 	objectIdentifier	[0]	BACnetObjectIdentifier,
 * 	propertyIdentifier	[1] BACnetPropertyIdentifier,
 * 	propertyArrayIndex	[2] Unsigned OPTIONAL, -- used only with array datatype
 * 	propertyValue	[3] ABSTRACT-SYNTAX.&Type
 *  priority	[4] Unsigned8 (1..16) OPTIONAL --used only when property is commandable
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fWritePropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * WritePropertyMultiple-Request ::= SEQUENCE {
 * 	listOfWriteAccessSpecifications	SEQUENCE OF WriteAccessSpecification
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fWritePropertyMultipleRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * DeviceCommunicationControl-Request ::= SEQUENCE {
 * 	timeDuration	[0] Unsigned16 OPTIONAL,
 *  enable-disable	[1] ENUMERATED {
 * 		enable (0),
 * 		disable (1)
 * 		},
 *  password	[2] CharacterString (SIZE(1..20)) OPTIONAL
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ConfirmedPrivateTransfer-Request ::= SEQUENCE {
 * 	vendorID	[0]	Unsigned,
 * 	serviceNumber	[1] Unsigned,
 * 	serviceParameters	[2] ABSTRACT-SYNTAX.&Type OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ConfirmedPrivateTransfer-ACK ::= SEQUENCE {
 * 	vendorID	[0]	Unsigned,
 * 	serviceNumber	[1] Unsigned,
 * 	resultBlock	[2] ABSTRACT-SYNTAX.&Type OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ConfirmedTextMessage-Request ::=  SEQUENCE {
 *  textMessageSourceDevice [0] BACnetObjectIdentifier,
 *  messageClass [1] CHOICE {
 *      numeric [0] Unsigned,
 *      character [1] CharacterString
 *      } OPTIONAL,
 *  messagePriority [2] ENUMERATED {
 *      normal (0),
 *      urgent (1)
 *      },
 *  message [3] CharacterString
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReinitializeDevice-Request ::= SEQUENCE {
 *  reinitializedStateOfDevice	[0] ENUMERATED {
 * 		coldstart (0),
 * 		warmstart (1),
 * 		startbackup (2),
 * 		endbackup (3),
 * 		startrestore (4),
 * 		endrestore (5),
 * 		abortrestor (6)
 * 		},
 *  password	[1] CharacterString (SIZE(1..20)) OPTIONAL
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * VTOpen-Request ::= SEQUENCE {
 *  vtClass	BACnetVTClass,
 *  localVTSessionIdentifier	Unsigned8
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fVtOpenRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * VTOpen-ACK ::= SEQUENCE {
 *  remoteVTSessionIdentifier	Unsigned8
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fVtOpenAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * VTClose-Request ::= SEQUENCE {
 *  listOfRemoteVTSessionIdentifiers	SEQUENCE OF Unsigned8
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fVtCloseRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * VTData-Request ::= SEQUENCE {
 *  vtSessionIdentifier	Unsigned8,
 *  vtNewData	OCTET STRING,
 *  vtDataFlag	Unsigned (0..1)
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fVtDataRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * VTData-ACK ::= SEQUENCE {
 *  allNewDataAccepted	[0] BOOLEAN,
 *  acceptedOctetCount	[1] Unsigned OPTIONAL -- present only if allNewDataAccepted = FALSE
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * Authenticate-Request ::= SEQUENCE {
 *  pseudoRandomNumber	[0] Unsigned32,
 *  excpectedInvokeID	[1] Unsigned8 OPTIONAL,
 *  operatorName	[2] CharacterString OPTIONAL,
 *  operatorPassword	[3] CharacterString (SIZE(1..20)) OPTIONAL,
 *  startEncypheredSession	[4] BOOLEAN OPTIONAL
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * Authenticate-ACK ::= SEQUENCE {
 *  modifiedRandomNumber	Unsigned32,
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fAuthenticateAck (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * RequestKey-Request ::= SEQUENCE {
 *  requestingDeviceIdentifier	BACnetObjectIdentifier,
 *  requestingDeviceAddress	BACnetAddress,
 *  remoteDeviceIdentifier	BACnetObjectIdentifier,
 *  remoteDeviceAddress	BACnetAddress
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fRequestKeyRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * Unconfirmed-Service-Request ::= CHOICE {
 * }
 * @param tvb 
 * @param tree 
 * @param offset
 * @param service_choice
 * @return modified offset
 */
static guint
fUnconfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice);

/**
 * UnconfirmedCOVNotification-Request ::= SEQUENCE {
 * 	subscriberProcessIdentifier	[0]	Unsigned32,
 * 	initiatingDeviceIdentifier	[1] BACnetObjectIdentifer,
 * 	monitoredObjectIdentifier	[2] BACnetObjectIdentifer,
 * 	timeRemaining	[3] unsigned,
 * 	listOfValues	[4] SEQUENCE OF BACnetPropertyValues
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * UnconfirmedEventNotification-Request ::= SEQUENCE {
 * 	ProcessIdentifier	[0]	Unsigned32,
 * 	initiatingDeviceIdentifier	[1] BACnetObjectIdentifer,
 * 	eventObjectIdentifier	[2] BACnetObjectIdentifer,
 * 	timeStamp	[3] BACnetTimeStamp,
 * 	notificationClass	[4] unsigned,
 * 	priority	[5] unsigned8,
 * 	eventType	[6] BACnetEventType,
 * 	messageText	[7] CharacterString OPTIONAL,
 * 	notifyType	[8] BACnetNotifyType,
 * 	ackRequired	[9] BOOLEAN OPTIONAL,
 * 	fromState	[10] BACnetEventState OPTIONAL,
 * 	toState	[11] BACnetEventState,
 * 	eventValues	[12] BACnetNotificationParameters OPTIONAL
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * I-Am-Request ::= SEQUENCE {
 * 	aAmDeviceIdentifier	BACnetObjectIdentifier,
 *  maxAPDULengthAccepted	Unsigned,
 * 	segmentationSupported	BACnetSegmentation,
 * 	vendorID	Unsigned
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fIAmRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset);


/**
 * I-Have-Request ::= SEQUENCE {
 * 	deviceIdentifier	BACnetObjectIdentifier,
 *  objectIdentifier	BACnetObjectIdentifier,
 * 	objectName	CharacterString
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fIHaveRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * UnconfirmedPrivateTransfer-Request ::= SEQUENCE {
 * 	vendorID	[0]	Unsigned,
 * 	serviceNumber	[1] Unsigned,
 * 	serviceParameters	[2] ABSTRACT-SYNTAX.&Type OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * UnconfirmedTextMessage-Request ::=  SEQUENCE {
 *  textMessageSourceDevice [0] BACnetObjectIdentifier,
 *  messageClass [1] CHOICE {
 *      numeric [0] Unsigned,
 *      character [1] CharacterString
 *      } OPTIONAL,
 *  messagePriority [2] ENUMERATED {
 *      normal (0),
 *      urgent (1)
 *      },
 *  message [3] CharacterString
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * TimeSynchronization-Request ::=  SEQUENCE {
 *  BACnetDateTime
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * UTCTimeSynchronization-Request ::=  SEQUENCE {
 *  BACnetDateTime
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fUTCTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * Who-Has-Request ::=  SEQUENCE {
 *  limits SEQUENCE {
 *      deviceInstanceRangeLowLimit [0] Unsigned (0..4194303),
 *      deviceInstanceRangeHighLimit [1] Unsigned (0..4194303)
 *      } OPTIONAL,
 *  object CHOICE {
 *      objectIdentifier [2] BACnetObjectIdentifier,
 *      objectName [3] CharacterString
 *      }
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * Who-Is-Request ::= SEQUENCE {
 * 	deviceInstanceRangeLowLimit	[0] Unsigned (0..4194303) OPTIONAL, -- must be used as a pair, see 16.9,
 * 	deviceInstanceRangeHighLimit	[0] Unsigned (0..4194303) OPTIONAL, -- must be used as a pair, see 16.9,
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fWhoIsRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnet-Error ::= CHOICE {
 *  addListElement          [8] ChangeList-Error,
 *  removeListElement       [9] ChangeList-Error,
 *  writePropertyMultiple   [16] WritePropertyMultiple-Error,
 *  confirmedPrivatTransfer [18] ConfirmedPrivateTransfer-Error,
 *  vtClose                 [22] VTClose-Error,
 *  readRange               [26] ObjectAccessService-Error
 *                      [default] Error
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @param service
 * @return modified offset
 */
static guint
fBACnetError(tvbuff_t *tvb, proto_tree *tree, guint offset, guint service);

/**
 * ChangeList-Error ::= SEQUENCE {
 *    errorType     [0] Error,
 *    firstFailedElementNumber  [1] Unsigned
 *    }
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * CreateObject-Error ::= SEQUENCE {
 *    errorType     [0] Error,
 *    firstFailedElementNumber  [1] Unsigned
 *    }
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fCreateObjectError(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ConfirmedPrivateTransfer-Error ::= SEQUENCE {
 *    errorType     [0] Error,
 *    vendorID      [1] Unsigned,
 *    serviceNumber [2] Unsigned,
 *    errorParameters   [3] ABSTRACT-SYNTAX.&Type OPTIONAL
 *    }
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fConfirmedPrivateTransferError(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * WritePropertyMultiple-Error ::= SEQUENCE {
 *    errorType     [0] Error,
 *    firstFailedWriteAttempt  [1] Unsigned
 *    }
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fWritePropertyMultipleError(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * VTClose-Error ::= SEQUENCE {
 *    errorType     [0] Error,
 *    listOfVTSessionIdentifiers  [1] SEQUENCE OF Unsigned8 OPTIONAL
 *    }
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fVTCloseError(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnet Application Types chapter 20.2.1
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param label 
 * @param src
 * @return modified offset
 */
static guint
fApplicationTypes   (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, const value_string *src);

/**
 * BACnetActionCommand ::= SEQUENCE {
 *  deviceIdentifier    [0] BACnetObjectIdentifier OPTIONAL,
 *  objectIdentifier    [1] BACnetObjectIdentifier,
 *  propertyIdentifier  [2] BACnetPropertyIdentifier,
 *  propertyArrayIndex  [3] Unsigned OPTIONAL, -- used only with array datatype
 *  propertyValue       [4] ABSTRACT-SYNTAX.&Type,
 *  priority            [5] Unsigned (1..16) OPTIONAL, -- used only when property is commandable
 *  postDelay           [6] Unsigned OPTIONAL,
 *  quitOnFailure       [7] BOOLEAN,
 *  writeSuccessful     [8] BOOLEAN
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetActionList ::= SEQUENCE {
 *  action  [0] SEQUENCE of BACnetActionCommand
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset);

/** BACnetAddress ::= SEQUENCE {
 *  network-number  Unsigned16, -- A value 0 indicates the local network
 *  mac-address     OCTET STRING -- A string of length 0 indicates a broadcast
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetAddressBinding ::= SEQUENCE {
 * 	deviceObjectID  BACnetObjectIdentifier
 * 	deviceAddress   BacnetAddress
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetCalendaryEntry ::= CHOICE {
 * 	date        [0] Date,
 * 	dateRange   [1] BACnetDateRange,
 *  weekNDay    [2] BacnetWeekNday
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetClientCOV ::= CHOICE {
 * 	real-increment  REAL,
 * 	default-increment   NULL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetCOVSubscription ::= SEQUENCE {
 *  Recipient                   [0] BACnetRecipientProcess,
 *  MOnitoredPropertyReference  [1] BACnetObjectPropertyReference,
 *  IssueConfirmedNotifications [2] BOOLEAN,
 *  TimeRemaining               [3] Unsigned,
 * 	COVIncrement                [4] REAL,
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fCOVSubscription (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetDailySchedule ::= SEQUENCE {
 *  day-schedule    [0] SENQUENCE OF BACnetTimeValue
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fDailySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetWeeklySchedule ::= SEQUENCE {
 *  week-schedule    SENQUENCE SIZE (7) OF BACnetDailySchedule
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetDateRange ::= SEQUENCE {
 *  StartDate   Date,
 *  EndDate     Date
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fDateRange (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetDateTime ::= SEQUENCE {
 *  date   Date,
 *  time   Time
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param label 
 * @return modified offset
 */
static guint
fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);

/**
 * BACnetDestination ::= SEQUENCE {
 *  validDays   BACnetDaysOfWeek,
 *  fromTime    Time,
 *  toTime      Time,
 *  recipient   BACnetRecipient,
 *  processIdentifier   Unsigned32,
 *  issueConfirmedNotifications BOOLEAN,
 *  transitions BACnetEventTransitionBits
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetDeviceObjectPropertyReference ::= SEQUENCE {
 *  objectIdentifier    [0] BACnetObjectIdentifier,
 *  propertyIdentifier  [1] BACnetPropertyIdentifier,
 *  propertyArrayIndex  [2] Unsigend OPTIONAL,
 *  deviceIdentifier    [3] BACnetObjectIdentifier OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fDeviceObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetDeviceObjectReference ::= SEQUENCE {
 *  deviceIdentifier    [0] BACnetObjectIdentifier OPTIONAL,
 *  objectIdentifier    [1] BACnetObjectIdentifier
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fDeviceObjectReference (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetEventParameter ::= CHOICE {
 * 	change-of-bitstring [0] SEQUENCE {
 *   	time-delay [0] Unsigned,
 *  	bitmask [1] BIT STRING,
 *   	list-of-bitstring-values [2] SEQUENCE OF BIT STRING
 *   	},
 *  change-of-state [1] SEQUENCE {
 *   	time-delay [0] Unsigned,
 *   	list-of-values [1] SEQUENCE OF BACnetPropertyStates
 *   	},
 *   change-of-value [2] SEQUENCE {
 *   	time-delay [0] Unsigned,
 *   	cov-criteria [1] CHOICE {
 *   		bitmask [0] BIT STRING,
 *   		referenced-property-increment [1] REAL
 *			}
 *		},
 *	command-failure [3] SEQUENCE {
 *		time-delay [0] Unsigned,
 *		feedback-property-reference [1] BACnetDeviceObjectPropertyReference
 *		},
 *	floating-limit [4] SEQUENCE {
 *		time-delay [0] Unsigned,
 *		setpoint-reference [1] BACnetDeviceObjectPropertyReference,
 *		low-diff-limit [2] REAL,
 *		high-diff-limit [3] REAL,
 *		deadband [4] REAL
 *		},
 *	out-of-range [5] SEQUENCE {
 *		time-delay [0] Unsigned,
 *		low-limit [1] REAL,
 *		high-limit [2] REAL,
 *		deadband [3] REAL
 *		},
 *	buffer-ready [7] SEQUENCE {
 *		notification-threshold [0] Unsigned,
 *		previous-notification-count [1] Unsigned32
 *		}
 *	change-of-life-safety [8] SEQUENCE {
 *		time-delay [0] Unsigned,
 *		list-of-life-safety-alarm-values [1] SEQUENCE OF BACnetLifeSafetyState,
 *		list-of-alarm-values [2] SEQUENCE OF BACnetLifeSafetyState,
 *		mode-property-reference [3] BACnetDeviceObjectPropertyReference
 *		}
 *	}
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset);


/**
 * BACnetLogRecord ::= SEQUENCE {
 *	timestamp [0] BACnetDateTime,
 *	logDatum [1] CHOICE {
 *		log-status [0] BACnetLogStatus,
 *		boolean-value [1] BOOLEAN,
 *		real-value [2] REAL,
 *		enum-value [3] ENUMERATED, -- Optionally limited to 32 bits
 *		unsigned-value [4] Unsigned, -- Optionally limited to 32 bits
 *		signed-value [5] INTEGER, -- Optionally limited to 32 bits
 *		bitstring-value [6] BIT STRING,-- Optionally limited to 32 bits
 *		null-value [7] NULL,
 *		failure [8] Error,
 *		time-change [9] REAL,
 *		any-value [10] ABSTRACT-SYNTAX.&Type -- Optional
 *		}
 *	statusFlags [2] BACnetStatusFlags OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetNotificationParameters ::= CHOICE {
 * 	change-of-bitstring	[0]	SEQUENCE {
 *      referenced-bitstring    [0] BIT STRING,
 *      status-flags    [1] BACnetStatusFlags
 *      },
 *  change-of-state [1]	SEQUENCE {
 *      new-state   [0] BACnetPropertyStatus,
 *      status-flags    [1] BACnetStatusFlags
 *      },
 *  change-of-value [2]	SEQUENCE {
 *      new-value   [0] CHOICE {
 *          changed-bits   [0] BIT STRING,
 *          changed-value    [1] REAL
 *          },
 *      status-flags    [1] BACnetStatusFlags
 *      },
 *  command-failure [3]	SEQUENCE {
 *      command-value   [0] ABSTRACT-SYNTAX.&Type, -- depends on ref property
 *      status-flags    [1] BACnetStatusFlags
 *      feedback-value    [2] ABSTRACT-SYNTAX.&Type -- depends on ref property
 *      },
 *  floating-limit [4]	SEQUENCE {
 *      reference-value   [0] REAL,
 *      status-flags    [1] BACnetStatusFlags
 *      setpoint-value   [2] REAL,
 *      error-limit   [3] REAL
 *      },
 *  out-of-range [5]	SEQUENCE {
 *      exceeding-value   [0] REAL,
 *      status-flags    [1] BACnetStatusFlags
 *      deadband   [2] REAL,
 *      exceeded-limit   [0] REAL
 *      },
 *  complex-event-type  [6] SEQUENCE OF BACnetPropertyValue,
 *  buffer-ready [7]	SEQUENCE {
 *      buffer-device   [0] BACnetObjectIdentifier,
 *      buffer-object    [1] BACnetObjectIdentifier
 *      previous-notification   [2] BACnetDateTime,
 *      current-notification   [3] BACnetDateTime
 *      },
 *  change-of-life-safety [8]	SEQUENCE {
 *      new-state   [0] BACnetLifeSafetyState,
 *      new-mode    [1] BACnetLifeSafetyState
 *      status-flags   [2] BACnetStatusFlags,
 *      operation-expected   [3] BACnetLifeSafetyOperation
 *      }
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetObjectPropertyReference ::= SEQUENCE {
 * 	objectIdentifier	[0] BACnetObjectIdentifier,
 * 	propertyIdentifier	[1] BACnetPropertyIdentifier,
 * 	propertyArrayIndex	[2] Unsigned OPTIONAL, -- used only with array datatype
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetObjectPropertyValue ::= SEQUENCE {
 *		objectIdentifier [0] BACnetObjectIdentifier,
 *		propertyIdentifier [1] BACnetPropertyIdentifier,
 *		propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
 *				-- if omitted with an array the entire array is referenced
 *		value [3] ABSTRACT-SYNTAX.&Type, --any datatype appropriate for the specified property
 *		priority [4] Unsigned (1..16) OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetPriorityArray ::= SEQUENCE SIZE (16) OF BACnetPriorityValue
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fPriorityArray (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetPropertyReference ::= SEQUENCE {
 * 	propertyIdentifier	[0] BACnetPropertyIdentifier,
 * 	propertyArrayIndex	[1] Unsigned OPTIONAL, -- used only with array datatype
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetPropertyValue ::= SEQUENCE {
 * 		PropertyIdentifier [0] BACnetPropertyIdentifier,
 * 		propertyArrayIndex [1] Unsigned OPTIONAL, -- used only with array datatypes
 * 				-- if omitted with an array the entire array is referenced
 * 		value [2] ABSTRACT-SYNTAX.&Type, -- any datatype appropriate for the specified property
 * 		priority [3] Unsigned (1..16) OPTIONAL -- used only when property is commandable
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnet Application PDUs chapter 21
 * BACnetRecipient::= CHOICE {
 * 	device	[0] BACnetObjectIdentifier
 * 	address	[1] BACnetAddress
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnet Application PDUs chapter 21
 * BACnetRecipientProcess::= SEQUENCE {
 * 	recipient	[0] BACnetRecipient
 * 	processID	[1] Unsigned32
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetSessionKey ::= SEQUENCE {
 * 	sessionKey	OCTET STRING (SIZE(8)), -- 56 bits for key, 8 bits for checksum
 * 	peerAddress	BACnetAddress
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 * @todo check if checksum is displayed correctly 
 */
static guint
fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetSetpointReference ::= SEQUENCE {
 * 	sessionKey	[0] BACnetObjectPropertyReference OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetSpecialEvent ::= SEQUENCE {
 * 	period		CHOICE {
 * 		calendarEntry		[0] BACnetCalendarEntry,
 * 		calendarRefernce	[1] BACnetObjectIdentifier
 * 		},
 * 		listOfTimeValues	[2] SEQUENCE OF BACnetTimeValue,
 * 		eventPriority		[3] Unsigned (1..16)
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fSpecialEvent (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetTimeStamp ::= CHOICE {
 * 	time			[0] Time,
 * 	sequenceNumber	[1] Unsigned (0..65535),
 * 	dateTime		[2] BACnetDateTime
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetTimeValue ::= SEQUENCE {
 * 	time	Time,
 * 	value	ABSTRACT-SYNTAX.&Type -- any primitive datatype, complex types cannot be decoded
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetVTSession ::= SEQUENCE {
 * 	local-vtSessionID	Unsigned8,
 * 	remote-vtSessionID	Unsigned8,
 * 	remote-vtAddress	BACnetAddress
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fVTSession (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnetWeekNDay ::= OCTET STRING (SIZE (3))
 * -- first octet month (1..12) January = 1, X'FF' = any month
 * -- second octet weekOfMonth where: 1 = days numbered 1-7
 * -- 2 = days numbered 8-14
 * -- 3 = days numbered 15-21
 * -- 4 = days numbered 22-28
 * -- 5 = days numbered 29-31
 * -- 6 = last 7 days of this month
 * -- X’FF’ = any week of this month
 * -- third octet dayOfWeek (1..7) where 1 = Monday
 * -- 7 = Sunday
 * -- X'FF' = any day of week
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReadAccessResult ::= SEQUENCE {
 * 	objectIdentifier	[0] BACnetObjectIdentifier,
 * 	listOfResults	[1] SEQUENCE OF SEQUENCE {
 * 		propertyIdentifier	[2] BACnetPropertyIdentifier,
 * 		propertyArrayIndex	[3] Unsigned OPTIONAL, -- used only with array datatype if omitted with an array the entire array is referenced
 * 		readResult	CHOICE {
 * 			propertyValue	[4] ABSTRACT-SYNTAX.&Type,
 * 			propertyAccessError	[5] Error
 * 		}
 *  } OPTIONAL
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * ReadAccessSpecification ::= SEQUENCE {
 * 	objectIdentifier	[0] BACnetObjectIdentifier,
 * 	listOfPropertyReferences	[1] SEQUENCE OF BACnetPropertyReference
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fReadAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset);

/**
 * WriteAccessSpecification ::= SEQUENCE {
 * 	objectIdentifier	[0] BACnetObjectIdentifier,
 * 	listOfProperty	[1] SEQUENCE OF BACnetPropertyValue
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset);


/********************************************************* Helper functions *******************************************/

/**
 * extracts the tag number from the tag header.
 * @param tvb "TestyVirtualBuffer"
 * @param offset in actual tvb
 * @return Tag Number corresponding to BACnet 20.2.1.2 Tag Number
 */
static guint
fTagNo (tvbuff_t *tvb, guint offset);
                                     
/**
 * splits Tag Header coresponding to 20.2.1 General Rules For BACnet Tags
 * @param tvb = "TestyVirtualBuffer"
 * @param offset = offset in actual tvb
 * @return tag_no BACnet 20.2.1.2 Tag Number
 * @return class_tag BACnet 20.2.1.1 Class
 * @return lvt BACnet 20.2.1.3 Length/Value/Type
 * @return offs = length of this header
 */

static guint
fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* class_tag, guint32 *lvt);


/**
 * adds processID with max 32Bit unsigned Integer Value to tree
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * adds timeSpan with max 32Bit unsigned Integer Value to tree
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);

/**
 * BACnet Application PDUs chapter 21
 * BACnetPropertyIdentifier::= ENUMERATED {
 * 	 @see bacapp_property_identifier
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @param tt returnvalue of this item 
 * @return modified offset
 */
static guint
fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset, proto_item **tt);

/**
 * listOfEventSummaries ::= SEQUENCE OF SEQUENCE {
 * 	objectIdentifier	[0] BACnetObjectIdentifier,
 *  eventState  [1] BACnetEventState,
 *  acknowledgedTransitions [2] BACnetEventTransitionBits,
 *  eventTimeStamps [3] SEQURNCE SIZE (3) OF BACnetTimeStamps,
 *  notifyType  [4] BACnetNotifyType,
 *  eventEnable [5] BACnetEventTransitionBits,
 *  eventPriorities [6] SEQUENCE SIZE (3) OF Unsigned
 * }
 * @param tvb 
 * @param tree
 * @param offset 
 * @return modified offset
 */
static guint
flistOfEventSummaries (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * SelectionCriteria ::= SEQUENCE {
 * 	propertyIdentifier	[0] BACnetPropertyIdentifier,
 * 	propertyArrayIndex	[1] Unsigned OPTIONAL, -- used only with array datatype
 *  relationSpecifier	[2] ENUMERATED { bacapp_relationSpecifier },
 *  comparisonValue	[3] ABSTRACT-SYNTAX.&Type
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fSelectionCriteria (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * objectSelectionCriteria ::= SEQUENCE {
 * 	selectionLogic	[0] ENUMERATED { bacapp_selectionLogic },
 * 	listOfSelectionCriteria	[1] SelectionCriteria
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset);

/**
 * ObjectSpecifier ::= CHOICE {
 * 	objectType	[0] BACnetObjectType,
 *  objectIdentifier	[1] BACnetObjectIdentifier
 * }
 * @param tvb 
 * @param tree 
 * @param offset 
 * @return modified offset
 */
static guint
fObjectSpecifier (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * BACnet-Error ::= SEQUENCE {
 *    error-class ENUMERATED {},
 *    error-code  ENUMERATED {}
 *    }
 * }
 * @param tvb
 * @param tree 
 * @param offset
 * @return modified offset
 */
static guint
fError(tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * realizes some ABSTRACT-SYNTAX.&Type
 * @param tvb
 * @param tree
 * @param offset
 * @return modified offset
 * @todo beautify this ugly construct
 */
static guint
fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset);

/**
 * register_bacapp
 */
void
proto_register_bacapp(void);

/**
 * proto_reg_handoff_bacapp
 */
void
proto_reg_handoff_bacapp(void);

#endif /* __BACAPP_H__ */


Index: epan/dissectors/packet-bacapp.c
===================================================================
--- epan/dissectors/packet-bacapp.c	(revision 13952)
+++ epan/dissectors/packet-bacapp.c	(working copy)
@@ -2,6 +2,8 @@
  * Routines for BACnet (APDU) dissection
  * Copyright 2001, Hartmut Mueller <hartmut@xxxxxxxxxxxx>, FH Dortmund
  *
+ * rewritten 2004, Herbert Lischka <lischka@xxxxxxxxxxxxxxxx>, Berlin
+ *
  * $Id$
  *
  * Ethereal - Network traffic analyzer
@@ -25,93 +27,5095 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "packet-bacapp.h"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+static const value_string
+BACnetTypeName[] = {
+	{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 }
+};
 
-#include <glib.h>
+static const true_false_string segments_follow = {
+	"Segmented Request",
+	"Unsegemented Request"
+};
 
-#include <epan/packet.h>
+static const true_false_string more_follow = {
+	"More Segments Follow",
+	"No More Segments Follow"
+};
 
-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];
-}
+static const true_false_string segmented_accept = {
+	"Segmented Response accepted",
+	"Segmented Response not accepted"
+};
 
+static const true_false_string
+BACnetTagClass = {
+	"Context Specific Tag",
+	"Application Tag"
+};
+
+static const value_string
+BACnetMaxSegmentsAccepted [] = {
+	{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
+BACnetMaxAPDULengthAccepted [] = {
+	{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
+BACnetRejectReason [] = {
+	{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
+BACnetTagNumber [] = {
+	{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
+BACnetAction [] = {
+	{0,"direct"},
+	{1,"reverse"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetFileAccessMethod [] = {
+	{0,"record-access"},
+	{1,"stream-access"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetAbortReason [] = {
+	{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
+BACnetLifeSafetyMode [] = {
+	{0,"off"},
+	{1,"on"},
+	{2,"test"},
+	{3,"manned"},
+	{4,"unmanned"},
+	{5,"armed"},
+	{6,"disarmed"},
+	{7,"prearmed"},
+	{8,"slow"},
+	{9,"fast"},
+	{10,"disconnected"},
+	{11,"enabledt"},
+	{12,"disabled"},
+	{13,"atomic-release-disabled"},
+	{14,"default"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetLifeSafetyOperation [] = {
+	{0,"none"},
+	{1,"silence"},
+	{2,"silence-audible"},
+	{3,"silence-visual"},
+	{4,"reset"},
+	{5,"reset-alarm"},
+	{6,"reset-fault"},
+	{7,"reserved by ASHRAE"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetLimitEnable [] = {
+	{0,"lowLimitEnable"},
+	{1,"highLimitEnable"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetLifeSafetyState [] = {
+	{0,"quiet"},
+	{1,"pre-alarm"},
+	{2,"alarm"},
+	{3,"fault"},
+	{4,"fault-pre-alarm"},
+	{5,"fault-alarm"},
+	{6,"not-ready"},
+	{7,"active"},
+	{8,"tamper"},
+	{9,"test-alarm"},
+	{10,"test-active"},
+	{11,"test-fault"},
+	{12,"test-fault-alarm"},
+	{13,"holdup"},
+	{14,"duress"},
+	{15,"tamper-alarm"},
+	{16,"abnormal"},
+	{17,"emergency-power"},
+	{18,"delayed"},
+	{19,"blocked"},
+	{20,"local-alarm"},
+	{21,"general-alarm"},
+	{22,"supervisory"},
+	{23,"test-supervisory"},
+	{256,"not known"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetConfirmedServiceChoice [] = {
+	{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
+BACnetReliability [] = {
+	{0,"no-fault-detected"},
+	{1,"no-sensor"},
+	{2,"over-range"},
+	{3,"under-range"},
+	{4,"open-loop"},
+	{5,"shorted-loop"},
+	{6,"no-output"},
+	{7,"unreliable-other"},
+	{8,"process-error"},
+	{9,"multi-state-fault"},
+	{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
+BACnetObjectType [] = {
+	{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
+BACnetUnits [] = {
+	{0,"Sq Meters"},
+	{1,"Sq Feet"},
+	{2,"Milliamperes"},
+	{3,"Amperes"},
+	{4,"Ohms"},
+	{5,"Volts"},
+	{6,"Kilovolts"},
+	{7,"Megavolts"},
+	{8,"Volt Amperes"},
+	{9,"Kilovolt Amperes"},
+	{10,"Megavolt Amperes"},
+	{11,"Volt Amperes Reactive"},
+	{12,"Kilovolt Amperes Reactive"},
+	{13,"Megavolt Amperes Ractive"},
+	{14,"Degrees Phase"},
+	{15,"Power Factor"},
+	{16,"Joules"},
+	{17,"Kilojoules"},
+	{18,"Watt Hours"},
+	{19,"Kilowatt Hours"},
+	{20,"BTUs"},
+	{21,"Therms"},
+	{22,"Ton Hours"},
+	{23,"Joules Per Kg Dry Air"},
+	{24,"BTUs Per Pound Dry Air"},
+	{25,"Cycles Per Hour"},
+	{26,"Cycles Per Minute"},
+	{27,"Hertz"},
+	{28,"Gramms Of Water Per Kilogram Dry Air"},
+	{29,"Relative Humidity"},
+	{30,"Millimeters"},
+	{31,"Meters"},
+	{32,"Inches"},
+	{33,"Feed"},
+	{34,"Watts Per Sq Foot"},
+	{35,"Watts Per Sq meter"},
+	{36,"Lumens"},
+	{37,"Lux"},
+	{38,"Foot Candels"},
+	{39,"Kilograms"},
+	{40,"Pounds Mass"},
+	{41,"Tons"},
+	{42,"Kgs per Second"},
+	{43,"Kgs Per Minute"},
+	{44,"Kgs Per Hour"},
+	{45,"Pounds Mass Per Minute"},
+	{46,"Pounds Mass Per Hour"},
+	{47,"Watt"},
+	{48,"Kilowatts"},
+	{49,"Megawatts"},
+	{50,"BTUs Per Hour"},
+	{51,"Horsepower"},
+	{52,"Tons Refrigeration"},
+	{53,"Pascals"},
+	{54,"Kilopascals"},
+	{55,"Bars"},
+	{56,"Pounds Force Per Square Inch"},
+	{57,"Centimeters Of Water"},
+	{58,"Inches Of Water"},
+	{59,"Millimeters Of Mercury"},
+	{60,"Centimeters Of Mercury"},
+	{61,"Inches Of Mercury"},
+	{62,"Degrees Celsius"},
+	{63,"Degress Kelvin"},
+	{64,"Degrees Fahrenheit"},
+	{65,"Degree Days Celsius"},
+	{66,"Degree Days Fahrenheit"},
+	{67,"Years"},
+	{68,"Months"},
+	{69,"Weeks"},
+	{70,"Days"},
+	{71,"Hours"},
+	{72,"Minutes"},
+	{73,"Seconds"},
+	{74,"Meters Per Second"},
+	{75,"Kilometers Per Hour"},
+	{76,"Feed Per Second"},
+	{77,"Feet Per Minute"},
+	{78,"Miles Per Hour"},
+	{79,"Cubic Feet"},
+	{80,"Cubic Meters"},
+	{81,"Imperial Gallons"},
+	{82,"Liters"},
+	{83,"US Gallons"},
+	{84,"Cubic Feet Per Minute"},
+	{85,"Cubic Meters Per Second"},
+	{86,"Imperial Gallons Per Minute"},
+	{87,"Liters Per Second"},
+	{88,"Liters Per Minute"},
+	{89,"US Gallons Per Minute"},
+	{90,"Degrees Angular"},
+	{91,"Degrees Celsius Per Hour"},
+	{92,"Degrees Celsius Per Minute"},
+	{93,"Degrees Fahrenheit Per Hour"},
+	{94,"Degrees Fahrenheit Per Minute"},
+	{95,"No Units"},
+	{96,"Parts Per Million"},
+	{97,"Parts Per Billion"},
+	{98,"Percent"},
+	{99,"Pecent Per Second"},
+	{100,"Per Minute"},
+	{101,"Per Second"},
+	{102,"Psi Per Degree Fahrenheit"},
+	{103,"Radians"},
+	{104,"Revolutions Per Min"},
+	{105,"Currency1"},
+	{106,"Currency2"},
+	{107,"Currency3"},
+	{108,"Currency4"},
+	{109,"Currency5"},
+	{110,"Currency6"},
+	{111,"Currency7"},
+	{112,"Currency8"},
+	{113,"Currency9"},
+	{114,"Currency10"},
+	{115,"Sq Inches"},
+	{116,"Sq Centimeters"},
+	{117,"BTUs Per Pound"},
+	{118,"Centimeters"},
+	{119,"Pounds Mass Per Second"},
+	{120,"Delta Degrees Fahrenheit"},
+	{121,"Delta Degrees Kelvin"},
+	{122,"Kilohms"},
+	{123,"Megohms"},
+	{124,"Millivolts"},
+	{125,"Kilojoules Per Kg"},
+	{126,"Megajoules"},
+	{127,"Joules Per Degree Kelvin"},
+	{128,"Joules Per Kg Degree Kelvin"},
+	{129,"Kilohertz"},
+	{130,"Megahertz"},
+	{131,"Per Hour"},
+	{132,"Milliwatts"},
+	{133,"Hectopascals"},
+	{134,"Millibars"},
+	{135,"Cubic Meters Per Hour"},
+	{136,"Liters Per Hour"},
+	{137,"KWatt Hours Per Square Meter"},
+	{138,"KWatt Hours Per Square Foot"},
+	{139,"Megajoules Per Square Meter"},
+	{140,"Megajoules Per Square Foot"},
+	{141,"Watts Per Sq Meter Degree Kelvin"},
+	{142,"Cubic Feet Per Second"},
+	{143,"Percent Obstruction Per Foot"},
+	{144,"Percent Obstruction Per Meter"},
+	{256,"Kelvin Per Minute"},
+	{257,"Minute Per Kelvin"},
+	{258,"Kelvin Per Hour"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetErrorCode [] = {
+	{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
+BACnetPropertyIdentifier [] = {
+	{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-schedule"},
+	{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
+BACnetBinaryPV [] = {
+	{0,"inactive"},
+	{1,"active"},
+	{0,NULL}
+};
+
+
+static const value_string
+BACnetCharacterSet [] = {
+	{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
+BACnetStatusFlags [] = {
+	{0,"in-alarm"},
+	{1,"fault"},
+	{2,"overridden"},
+	{3,"out-of-service"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetMessagePriority [] = {
+	{0,"normal"},
+	{1,"urgent"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetAcknowledgementFilter [] = {
+	{0,"and"},
+	{1,"or"},
+	{2,"all"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetResultFlags [] = {
+	{0,"firstitem"},
+	{1,"lastitem"},
+	{2,"moreitems"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetRelationSpecifier [] = {
+	{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
+BACnetSelectionLogic [] = {
+	{0,"normal"},
+	{1,"urgent"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetEventStateFilter [] = {
+	{0,"offnormal"},
+	{1,"fault"},
+	{2,"normal"},
+	{3,"all"},
+	{4,"active"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetEventTransitionBits [] = {
+	{0,"to-offnormal"},
+	{1,"to-fault"},
+	{2,"to-normal"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetSegmentation [] = {
+	{0,"segmented-both"},
+	{1,"segmented-transmit"},
+	{2,"segmented-receive"},
+	{3,"no-segmentation"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetSilencedState [] = {
+	{0,"unsilenced"},
+	{1,"audible-silenced"},
+	{2,"visible-silenced"},
+	{3,"all-silenced"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetDeviceStatus [] = {
+	{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
+BACnetEnableDisable [] = {
+	{0,"enable"},
+	{1,"disable"},
+	{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,"any month" },
+	{0,NULL }
+};
+
+static const value_string
+weekofmonth [] = {
+	{1,"days numbered 1-7" },
+	{2,"days numbered 8-14" },
+	{3,"days numbered 15-21" },
+	{4,"days numbered 22-28" },
+	{5,"days numbered 29-31" },
+	{6,"last 7 days of this month" },
+	{255,"any week of this month" },
+	{0,NULL }
+};
+
+static const value_string
+days [] = {
+	{1,"Monday" },
+	{2,"Tuesday" },
+	{3,"Wednesday" },
+	{4,"Thursday" },
+	{5,"Friday" },
+	{6,"Saturday" },
+	{7,"Sunday" },
+	{255,"any day of week" },
+	{0,NULL },
+};
+
+static const value_string
+BACnetErrorClass [] = {
+	{0,"device" },
+	{1,"object" },
+	{2,"property" },
+	{3,"resources" },
+	{4,"security" },
+	{5,"services" },
+	{6,"vt" },
+	{0,NULL },
+};
+
+static const value_string
+BACnetVTClass [] = {
+	{0,"default-terminal" },
+	{1,"ansi-x3-64" },
+	{2,"dec-vt52" },
+	{3,"dec-vt100" },
+	{4,"dec-vt200" },
+	{5,"hp-700-94" },
+	{6,"ibm-3130" },
+	{0,NULL },
+};
+
+static const value_string
+BACnetEventType [] = {
+	{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
+BACnetEventState [] = {
+	{0,"normal" },
+	{1,"fault" },
+	{2,"offnormal" },
+	{3,"high-limit" },
+	{4,"low-limit" },
+	{5,"life-safety-alarm" },
+	{0,NULL },
+};
+
+static const value_string
+BACnetLogStatus [] = {
+	{0,"log-disabled" },
+	{1,"buffer-purged" },
+	{0,NULL },
+};
+
+static const value_string
+BACnetMaintenance [] = {
+	{0,"none" },
+	{1,"periodic-test" },
+	{2,"need-service-operational" },
+	{3,"need-service-inoperative" },
+	{0,NULL },
+};
+
+static const value_string
+BACnetNotifyType [] = {
+	{0,"alarm" },
+	{1,"event" },
+	{2,"ack-notification" },
+	{0,NULL },
+};
+
+static const value_string
+BACnetServicesSupported [] = {
+	{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
+BACnetPropertyStates [] = {
+	{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 const value_string
+BACnetProgramError [] = {
+	{0,"normal"},
+	{1,"load-failed"},
+	{2,"internal"},
+	{3,"program"},
+	{4,"other"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetProgramRequest [] = {
+	{0,"ready"},
+	{1,"load"},
+	{2,"run"},
+	{3,"halt"},
+	{4,"restart"},
+	{4,"unload"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetProgramState [] = {
+	{0,"idle"},
+	{1,"loading"},
+	{2,"running"},
+	{3,"waiting"},
+	{4,"halted"},
+	{4,"unloading"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetReinitializedStateOfDevice [] = {
+	{0,"coldstart"},
+	{1,"warmstart"},
+	{2,"startbackup"},
+	{3,"endbackup"},
+	{4,"startrestore"},
+	{5,"endrestore"},
+	{6,"abortrestore"},
+	{0,NULL}
+};
+
+static const value_string
+BACnetPolarity [] = {
+	{0,"normal"},
+	{1,"reverse"},
+	{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_objectType = -1;
+static int hf_bacapp_instanceNumber = -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_BACnetRejectReason = -1;
+static int hf_BACnetAbortReason = -1;
+static int hf_BACnetTagNumber = -1;
+static int hf_BACnetTagClass = -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_vpart = -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 gint ett_bacapp_list = -1;
+static gint ett_bacapp_value = -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;
+
+static guint
+fTagNo (tvbuff_t *tvb, guint offset)
 {
-	proto_item *ti;
+	return (guint)(tvb_get_guint8(tvb, offset) >> 4);
+}
+
+static guint
+fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* class_tag, guint32 *lvt)
+{
+	guint8 tmp;
+	guint offs = 1;
+
+	tmp = tvb_get_guint8(tvb, offset);
+	*class_tag = tmp & 0x08; /* 0 = Application Tag, 1 = Context Specific Tag */
+	*lvt = tmp & 0x07;
+	*tag_no = tmp >> 4;
+	if (*tag_no == 15) { /* B'1111' because of extended tagnumber */
+		*tag_no = tvb_get_guint8(tvb, offset + offs++);
+	}
+	if (*lvt == 5) {       /* length is more than 4 Bytes */
+		*lvt = tvb_get_guint8(tvb, offset + offs++);
+		if (*lvt == 254) { /* length is encoded with 16 Bits */
+			*lvt = tvb_get_guint8(tvb, offset + offs++);
+			*lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
+		} else {
+            if (*lvt == 255) { /* length is encoded with 32 Bits */
+			*lvt = tvb_get_guint8(tvb, offset + offs++);
+			*lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
+			*lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
+			*lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
+            }
+        }
+	}
+
+	return offs;
+}
+
+static guint
+fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+	guint8 tmp, i;
+	guint64 val = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+    guint offs;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	for (i = 0; i < min(lvt,8); i++) {
+		tmp = tvb_get_guint8(tvb, offset+offs+i);
+		val = (val << 8) + tmp;
+	}
+	proto_tree_add_text(tree, tvb, offset, min(lvt,8)+offs, "%s%" PRIu64, LABEL(label), val);
+	return offset+offs+min(lvt,8);
+}
+
+static guint
+fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+	guint8 tmp, i;
+	guint64 val = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+    guint offs;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	for (i = 0; i < min(lvt,8); i++) {
+		tmp = tvb_get_guint8(tvb, offset+offs+i);
+		val = (val << 8) + tmp;
+	}
+	proto_tree_add_text(tree, tvb, offset, min(lvt,8)+offs, "%s%" PRId64, LABEL(label), (gint64) val);
+	return offset+offs+min(lvt,8);
+}
+
+static guint
+fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint8 tmp, i;
+	guint32 val = 0, lvt;
+	guint8 tag_no, class_tag;
+    guint offs;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	for (i = 0; i < min(lvt, 4); i++) {
+			tmp = tvb_get_guint8(tvb, offset+offs+i);
+			val = (val << 8) + tmp;
+	}
+	
+	proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, offset, offs+i, val);
+	return offset+offs+i;
+}
+
+static guint
+fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+	guint8 tmp, i;
+	guint val = 0;
+	guint32 lvt;
+	guint8 tag_no, class_tag;
+    guint offs;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	for (i = 0; i < min(lvt, 4); i++) {
+		tmp = tvb_get_guint8(tvb, offset+offs+i);
+		val = (val << 8) + tmp;
+	}
+	proto_tree_add_text(tree, tvb, offset, i+offs, "%s (hh.mm.ss): %d.%02d.%02d%s", LABEL(label), (val / 3600), ((val % 3600) / 60), (val % 60), val == 0 ? " (indefinite)" : "");
+	return offset+offs+i;
+}
+
+static guint
+fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint32 month, weekOfMonth, dayOfWeek;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+    guint offs;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	month = tvb_get_guint8(tvb, offset+offs);
+	weekOfMonth = tvb_get_guint8(tvb, offset+offs+1);
+	dayOfWeek = tvb_get_guint8(tvb, offset+offs+2);
+	proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s %s, %s", 
+                        val_to_str(month, months, "month (%d) not found"), 
+                        val_to_str(weekOfMonth, weekofmonth, "week of month (%d) not found"), 
+                        val_to_str(dayOfWeek, days, "day of week (%d) not found"));
+	return offset+offs+lvt;
+}
+
+static guint
+fDate    (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+	guint32 year, month, day, weekday;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+    guint offs;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	year = tvb_get_guint8(tvb, offset+offs) + 1900;
+	month = tvb_get_guint8(tvb, offset+offs+1);
+	day = tvb_get_guint8(tvb, offset+offs+2);
+	weekday = tvb_get_guint8(tvb, offset+offs+3);
+	if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
+		proto_tree_add_text(tree, tvb, offset, lvt+offs, "%sany", LABEL(label));
+	else
+		proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%s %d, %d, (Day of Week = %s)", 
+                            LABEL(label), val_to_str(month, months, "month (%d) not found"), 
+                            day, year, val_to_str(weekday, days, "(%d) not found"));
+	return offset+offs+lvt;
+}
+
+static guint
+fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+	guint32 year, month, day, weekday, lvt;
+	guint8 tag_no, class_tag;
+	guint offs;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	year = tvb_get_guint8(tvb, offset+offs);
+	month = tvb_get_guint8(tvb, offset+offs+1);
+	day = tvb_get_guint8(tvb, offset+offs+2);
+	weekday = tvb_get_guint8(tvb, offset+offs+3);
+	if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
+		proto_tree_add_text(tree, tvb, offset, lvt+offs, "%sany", LABEL(label));
+	else
+		proto_tree_add_text(tree, tvb, offset, lvt+offs, "%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);
+	return offset+offs+lvt;
+}
+
+static guint
+fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	if (label != NULL) {
+		tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", LABEL(label));
+		subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+	}
+	offset = fDate    (tvb,subtree,offset,"Date: ");
+	return fTime (tvb,subtree,offset,"Time: ");
+}
+
+static guint
+fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;                               
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+        if (((lvt == 7) && class_tag)) {   /* closing Tag, but not for me */
+            return offset;
+        }
+		offset = fTime    (tvb,tree,offset,"Time: ");
+		offset = fApplicationTypes (tvb,tree,offset, "Value: ", NULL);
+	}
+	return offset;
+}
+
+static guint
+fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* Date */
+			offset = fDate    (tvb, tree, offset, "Date: ");
+			break;
+		case 1:	/* dateRange */
+			offset = fDateRange (tvb, tree, offset);
+			break;
+		case 2:	/* BACnetWeekNDay */
+			offset = fWeekNDay (tvb, tree, offset);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset < tvb_reported_length(tvb)) {	/* don't loop, it's a CHOICE */
+	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* time */
+			offset = fTime    (tvb, tree, offset, "timestamp: ");
+			break;
+		case 1:	/* sequenceNumber */
+			offset = fUnsignedTag (tvb, tree, offset, "sequence Number: ");
+			break;
+		case 2:	/* dateTime */
+			offset = fDateTime (tvb, tree, offset, "timestamp: ");
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* setpointReference */
+			offset = fObjectPropertyReference (tvb,tree,offset);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+
+static guint
+fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset < tvb_reported_length(tvb)) {
+        offset = fApplicationTypes (tvb,tree,offset, "increment: ",NULL);
+    }
+    return offset;
+}
+
+static guint
+fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset < tvb_reported_length(tvb)) {
+        offset = fApplicationTypes (tvb,tree,offset, "valid Days: ", days);
+        offset = fTime (tvb,tree,offset,"from time: ");
+        offset = fTime (tvb,tree,offset,"to time: ");
+        offset = fRecipient (tvb,tree,offset);
+        offset = fProcessId (tvb,tree,offset);
+        offset = fApplicationTypes (tvb,tree,offset,"issue confirmed notifications: ", NULL);
+        offset = fApplicationTypes (tvb,tree,offset,"transitions: ", BACnetEventTransitionBits);
+    }
+    return offset;
+}
+
+static guint
+fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, guint32 lvt)
+{
+	guint8 *str_val;
+    guint len;
+
+	if ((lvt == 0) || ((lvt+offset) > tvb_length(tvb)))
+		lvt = tvb_length(tvb) - offset;
+
+	proto_tree_add_text(tree, tvb, offset, lvt, "[displayed OctetString with %d Bytes:] %s", lvt, LABEL(label));
+
+	do {
+		len = 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) < tvb_reported_length(tvb)) {
+		proto_tree_add_text(tree, tvb, offset, tvb_reported_length(tvb) - tvb_length(tvb), "[Frame is %d Bytes shorter than expected]", tvb_reported_length(tvb) - tvb_length(tvb));
+		str_val = tvb_get_string(tvb, offset, 1);
+		g_free(str_val);
+	}
+	return offset;
+}
+
+static guint
+fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+    guint offs;
+
+	offset = fUnsignedTag (tvb, tree, offset, "network-number");
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	if (lvt == 0) {
+		proto_tree_add_text(tree, tvb, offset, offs, "mac-address: broadcast");
+		offset += offs;
+	} else
+		offset = fOctetString (tvb, tree, offset, "mac-address: ", lvt);
+	return offset;
+}
+
+static guint
+fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	offset = fOctetString (tvb,tree,offset,"session key: ", 8);
+	return fAddress (tvb,tree,offset);
+}
+
+static guint
+fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint8  tag_no, class_tag;
+	guint32 lvt;
+	guint offs;
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	proto_tree_add_item(tree, hf_bacapp_objectType, tvb, offset+offs, 4, FALSE);
+	proto_tree_add_item(tree, hf_bacapp_instanceNumber, tvb, offset+offs, 4, FALSE);
+
+	return offset+offs+4;
+}
+
+static guint
+fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* device */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 1:	/* address */
+			offset = fAddress (tvb, tree, offset);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* recipient */
+			offset = fRecipient (tvb, tree, offset);
+			break;
+		case 1:	/* processId */
+			offset = fProcessId (tvb, tree, offset);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	offset = fObjectIdentifier (tvb, tree, offset);
+	return fAddress (tvb, tree, offset);
+}
+
+static guint
+fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+        if (((lvt == 7) && class_tag)) {   /* closing Tag */
+            subtree = tree;
+            offset++;
+            continue;
+        }
+		switch (tag_no) {
+	
+		case 0: /* deviceIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1: /* objectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+        case 2: /* propertyIdentifier */
+            offset = fPropertyIdentifier (tvb,subtree,offset,&tt);
+            subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+            break;
+        case 3: /* propertyArrayIndex */
+            offset = fUnsignedTag (tvb,subtree,offset,"Property Array Index: ");
+            break;
+		case 4: /* propertyValue */
+			if (((lvt == 6) && class_tag)) { offset++;  /* opening Tag */
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+        case 5: /* priority */
+            offset = fUnsignedTag (tvb,subtree,offset,"Priority: ");
+            break;
+        case 6: /* quitOnFailure */
+            offset = fApplicationTypes   (tvb,subtree,offset,"Quit On Failure: ",NULL);
+            break;
+        case 7: /* writeSuccessful */
+            offset = fApplicationTypes   (tvb,subtree,offset,"Write Successful: ",NULL);
+            break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	return fActionCommand (tvb,tree,offset);
+}
+
+static guint
+fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset, proto_item **tt)
+{
+	guint8 tag_no, class_tag, tmp, i;
+	guint32 lvt;
+    guint offs;
+	propertyIdentifier = 0;	/* global Variable */
+
+	offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	for (i = 0; i < min(lvt,4); i++) {
+		tmp = tvb_get_guint8(tvb, offset+offs+i);
+		propertyIdentifier = (propertyIdentifier << 8) + tmp;
+	}
+	*tt = proto_tree_add_text(tree, tvb, offset, min(lvt,4)+offs,
+		"property Identifier: %s", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "(%d) reserved for ASHREA"));
+	return offset+offs+min(lvt,4); 
+}
+
+static guint
+fApplicationTypes   (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, const value_string *src)
+{
+	guint8 tag_no, class_tag, tmp, i, j, unused;
+	guint64 val = 0;
+    guint32 lvt;
+    guint offs;
+	gfloat f_val = 0.0;
+	gdouble d_val = 0.0;
+	guint8 *str_val;
+	guint8 bf_arr[256];
+
+	if (offset < tvb_reported_length(tvb)) {
+
+		offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	
+		switch (tag_no) {
+			case 0:	/** NULL 20.2.2 */
+				proto_tree_add_text(tree, tvb, offset++, 1, "%sNULL", LABEL(label));
+				break;
+			case 1:	/** BOOLEAN 20.2.3 */
+				proto_tree_add_text(tree, tvb, offset++, 1, "%s%s", LABEL(label), lvt == 0 ? "FALSE" : "TRUE");
+				break;
+			case 2:	/** Unsigned Integer 20.2.4 */
+				offset = fUnsignedTag (tvb, tree, offset, label);
+				break;
+			case 3:	/** Signed Integer 20.2.5 */
+				offset = fSignedTag (tvb, tree, offset, label);
+				break;
+			case 4:	/** Real 20.2.6 */
+				f_val = tvb_get_ntohieee_float(tvb, offset+offs);
+				proto_tree_add_text(tree, tvb, offset, 4+offs, "%s%f", LABEL(label), f_val);
+				offset +=4+offs;
+				break;
+			case 5:	/** Double 20.2.7 */
+				d_val = tvb_get_ntohieee_double(tvb, offset+offs);
+				proto_tree_add_text(tree, tvb, offset, 8+offs, "%s%lf", LABEL(label), d_val);
+				offset+=8+offs;
+				break;
+			case 6: /** Octet String 20.2.8 */
+				proto_tree_add_text(tree, tvb, offset, 1, "%s (%d Characters)", LABEL(label), lvt);
+				offset = fOctetString (tvb, tree, offset+offs, label, lvt);
+				break;
+			case 7: /** Character String 20.2.9 */
+				tmp = tvb_get_guint8(tvb, offset+offs);
+				if (tmp == 3) {
+					proto_tree_add_text (tree, tvb, offset, 4+offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
+					offset+=4+offs;
+					lvt-=4;
+				}
+				if (tmp == 4) {
+					proto_tree_add_text (tree, tvb, offset, 1+offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
+					offset+=1+offs;
+					lvt-=1;
+				}
+				if ((tmp != 3) && (tmp != 4)) {
+					proto_tree_add_text (tree, tvb, offset, offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
+					offset+=1+offs;
+					lvt--;
+				}
+				do {
+					guint l = min(lvt, 255);
+					str_val = tvb_get_string(tvb, offset, l);
+					/** this decoding may be 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 20.2.10 */
+				offset+=offs;
+				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+lvt-1);	/* now the last 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, 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+=lvt;
+				break;
+			case 9: /** Enumerated 20.2.11 */
+				for (i = 0; i < min(lvt,8); i++) {
+					tmp = tvb_get_guint8(tvb, offset+offs+i);
+					val = (val << 8) + tmp;
+				}
+				if (src != NULL)
+					proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%s (%d)", LABEL(label), val_to_str((guint) val, src, "Reserved by ASHRAE"), (guint) val);
+				else
+					proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%" PRIu64, LABEL(label), val);
+	
+				offset+=lvt+offs;
+				break;
+			case 10: /** Date 20.2.12 */
+				offset = fDate    (tvb, tree, offset, label);
+				break;
+			case 11: /** Time 20.2.13 */
+				offset = fTime (tvb, tree, offset, label);
+				break;
+			case 12: /** BACnetObjectIdentifier 20.2.14 */
+				offset = fObjectIdentifier (tvb, tree, offset);
+				break;
+			case 13: /* reserved for ASHRAE */
+			case 14:
+			case 15:
+				proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s'reserved for ASHRAE'", LABEL(label));
+				offset+=lvt+offs;
+				break;
+			default:
+				return offset;
+				break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	guint offs, lastoffset = 0;
+	char ar[256];
+	sprintf (ar, "%s: ", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "identifier (%d) not found"));
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) { /* closing tag, but not for me */
+			return offset;
+		}
+		/* Application Tags */
+		switch (propertyIdentifier) {
+		case 2: /* BACnetActionList */
+			offset = fActionList (tvb,tree,offset);
+			break;
+		case 30: /* BACnetAddressBinding */
+			offset = fAddressBinding (tvb,tree,offset);
+			break;
+		case 97: /* Protocol-Services-Supported */
+			offset = fApplicationTypes   (tvb, tree, offset, ar, BACnetServicesSupported);
+			break;
+		case 111: /* Status-Flags */
+		case 112: /* System-Status */
+			offset = fApplicationTypes   (tvb, tree, offset, ar, BACnetStatusFlags);
+			break;
+		case 117: /* units */
+			offset = fApplicationTypes   (tvb, tree, offset, ar, BACnetUnits);
+			break;
+		case 76:  /* object-list */
+			offset = fApplicationTypes   (tvb, tree, offset, ar, NULL);
+			break;
+		case 87:	/* priority-array */
+			offset = fPriorityArray  (tvb, tree, offset);
+			break;
+		case 123:	/* weekly-schedule */
+			offset = fWeeklySchedule (tvb,tree,offset);
+			break;
+		default:
+			offset = fApplicationTypes   (tvb, tree, offset, ar, NULL);
+			break;
+		}
+	}
+	return offset;
+
+}
+
+static guint
+fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+    gboolean awaitingClosingTag = false;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (class_tag) {
+			if ((lvt == 7) && !awaitingClosingTag) {  /* closing Tag */
+				return offset; /* but not for me */
+			}
+			if (lvt == 7) {   /* closing Tag for me */
+				subtree = tree;
+				offset++;
+				awaitingClosingTag = false;
+				continue;
+			}
+			switch (tag_no) {
+			case 0:	/* PropertyIdentifier */
+				offset = fPropertyIdentifier (tvb, subtree, offset,  &tt);
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				break;
+			case 1:	/* propertyArrayIndex */
+				offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+				break;
+			case 2:  /* Value */
+				if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+					awaitingClosingTag = true;
+					offset = fAbstractSyntaxNType (tvb, subtree, offset);
+					break;
+				}
+				FAULT;
+				break;
+			case 3:  /* Priority */
+				offset = fSignedTag (tvb, subtree, offset, "Priority: ");
+				break;
+			default:
+				return offset;
+				break;
+			}
+		} else {
+			offset = fAbstractSyntaxNType (tvb,tree,offset);
+		}
+	}
+	return offset;
+}
+
+static guint
+fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* ProcessId */
+			offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
+			break;
+		case 1: /* monitored ObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+		break;
+		case 2: /* issueConfirmedNotifications */
+			offset = fApplicationTypes   (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
+			break;
+		case 3:	/* life time */
+			offset = fTimeSpan (tvb,tree,offset,"life time");
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fCOVSubscription(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* Recipient */
+			offset = fRecipientProcess (tvb, tree, offset);
+			break;
+		case 1: /* monitoredPropertyReference */
+			offset = fPropertyReference (tvb, tree, offset);
+		break;
+		case 2: /* issueConfirmedNotifications */
+			offset = fApplicationTypes   (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
+			break;
+        case 3:	/* time remaining */
+            offset = fTimeSpan (tvb,tree,offset,"time remaining");
+			break;
+        case 4: /* COVIncrement */
+            offset = fApplicationTypes(tvb,tree,offset,"COV Increment: ", NULL);
+            break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb, offset)) {
+		case 0: /* deviceInstanceLowLimit */
+			offset = fUnsignedTag (tvb, tree, offset, "device Instance Low Limit: ");
+			break;
+		case 1: /* deviceInstanceHighLimit */
+			offset = fUnsignedTag (tvb, tree, offset, "device Instance High Limit: ");
+			break;
+		case 2: /* BACnetObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+		break;
+		case 3: /* messageText */
+			offset = fApplicationTypes   (tvb, tree, offset, "Object Name: ", NULL);
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+
+static guint
+fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) {   /* closing Tag */
+			offset++;
+			return offset;
+		}
+		
+		switch (tag_no) {
+		case 0: /* day-schedule */
+			if (((lvt == 6) && class_tag)) { offset++;  /* opening Tag */
+				offset = fTimeValue (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	guint i=1;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+	
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) {   /* closing Tag */
+			offset++;
+			return offset;
+		}	
+		tt = proto_tree_add_text(tree, tvb, offset, 0, val_to_str(i++, days, "day of week (%d) not found"));
+		subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+		offset = fDailySchedule (tvb,subtree,offset);
+	
+	}
+	return offset;
+}
+
+
+static guint
+fUTCTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+	
+	return fDateTime (tvb, tree, offset, "UTC-Time: ");
+}
+
+static guint
+fTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+
+	return fDateTime (tvb, tree, offset, NULL);
+}
+
+static guint
+fDateRange  (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+    offset = fDate (tvb,tree,offset,"Start Date: ");
+	return fDate (tvb, tree, offset, "End Date: ");
+}
+
+static guint
+fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* textMessageSourceDevice */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 1: /* messageClass */
+			switch (fTagNo(tvb, offset)) {
+			case 0: /* numeric */
+				offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
+				break;
+			case 1: /* character */
+				offset = fApplicationTypes   (tvb, tree, offset, "message Class: ", NULL);
+				break;
+			}
+			break;
+		case 2: /* messagePriority */
+			offset = fApplicationTypes   (tvb, tree, offset, "Object Name: ", BACnetMessagePriority);
+			break;
+		case 3: /* message */
+			offset = fApplicationTypes   (tvb, tree, offset, "message: ", NULL);
+			break;
+		default:
+			return offset;
+			break;	
+		}
+	}
+	return offset;
+}
+
+static guint
+fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* textMessageSourceDevice */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 1: /* messageClass */
+			switch (fTagNo(tvb, offset)) {
+			case 0: /* numeric */
+				offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
+				break;
+			case 1: /* character */
+				offset = fApplicationTypes   (tvb, tree, offset, "message Class: ", NULL);
+				break;
+			}
+			break;
+		case 2: /* messagePriority */
+			offset = fApplicationTypes   (tvb, tree, offset, "Object Name: ", BACnetMessagePriority);
+			break;
+		case 3: /* message */
+			offset = fApplicationTypes   (tvb, tree, offset, "message: ", NULL);
+			break;
+		default:
+			return offset;
+			break;	
+		}
+	}
+	return offset;
+}
+
+static guint
+fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+        if (((lvt == 7) && class_tag)) {   /* closing Tag */
+            subtree = tree;
+            offset++;
+            continue;
+        }
+		switch (tag_no) {
+	
+		case 0: /* vendorID */
+			offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
+			break;
+		case 1: /* serviceNumber */
+			offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
+			break;
+		case 2: /*serviceParameters */
+			if (((lvt == 6) && class_tag)) { offset++;  /* opening Tag */
+				tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+
+static guint
+fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+        if (((lvt == 7) && class_tag)) {   /* closing Tag */
+            subtree = tree;
+            offset++;
+            continue;
+        }
+		switch (tag_no) {
+	
+		case 0: /* vendorID */
+			offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
+			break;
+		case 1: /* serviceNumber */
+			offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
+			break;
+		case 2: /*serviceParameters */
+			if (((lvt == 6) && class_tag)) { offset++;   /* opening Tag */
+				tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+        if (((lvt == 7) && class_tag)) {   /* closing Tag */
+            subtree = tree;
+            offset++;
+            continue;
+        }
+		switch (tag_no) {
+	
+		case 0: /* vendorID */
+			offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
+			break;
+		case 1: /* serviceNumber */
+			offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
+			break;
+		case 2: /*serviceParameters */
+			if (((lvt == 6) && class_tag)) { offset++;   /* opening Tag */
+				tt = proto_tree_add_text(subtree, tvb, offset, 1, "result Block");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	if (label != NULL) {
+		tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", LABEL(label));
+		subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+	}
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	
+		switch (tag_no) {
+		case 0:	/* subscriberProcessId */
+			offset = fUnsignedTag (tvb, subtree, offset, "requesting Process Id: ");
+			break;
+		case 1: /* requestingSource */
+			offset = fApplicationTypes   (tvb, subtree, offset, "requesting Source: ", NULL);
+			break;
+		case 2: /* request */
+			offset = fApplicationTypes   (tvb, subtree, offset, "request: ", BACnetLifeSafetyOperation);
+			break;
+		case 3:	/* objectId */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0: /* change-of-bitstring */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fApplicationTypes   (tvb, tree, offset, "referenced-bitstring: ", NULL);
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+					break;
+				default:
+					return offset;
+					break;
+				}
+			}
+        break;
+		case 1: /* change-of-state */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fApplicationTypes   (tvb, tree, offset, "new-state: ", BACnetPropertyStates);
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+					break;
+				default:
+					return offset;
+					break;
+				}
+			}
+			break;
+        case 2: /* change-of-value */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0: offset++;
+					switch (fTagNo(tvb, offset)) {
+					case 0:
+						offset = fApplicationTypes   (tvb, tree, offset, "changed-bits: ", NULL);
+					break;
+					case 1:
+						offset = fApplicationTypes   (tvb, tree, offset, "changed-value: ", NULL);
+					break;
+					default:
+						return offset;
+						break;
+					}
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+				default:
+					return offset;
+					break;
+				}
+			}
+		break;
+        case 3: /* command-failure */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0: /* "command-value: " */
+					offset = fAbstractSyntaxNType   (tvb, tree, offset);
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+				case 2: /* "feedback-value: " */
+					offset = fAbstractSyntaxNType   (tvb, tree, offset);
+				default:
+					return offset;
+					break;
+				}
+			}
+        break;
+        case 4: /* floating-limit */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fApplicationTypes   (tvb, tree, offset, "reference-value: ", NULL);
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+					break;
+				case 2:
+					offset = fApplicationTypes   (tvb, tree, offset, "setpoint-value: ", NULL);
+					break;
+				case 3:
+					offset = fApplicationTypes   (tvb, tree, offset, "error-limit: ", NULL);
+				default:
+					return offset;
+					break;
+				}
+			}
+			break;
+        case 5: /* out-of-range */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fApplicationTypes   (tvb, tree, offset, "exceeding-value: ", NULL);
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+					break;
+				case 2:
+					offset = fApplicationTypes   (tvb, tree, offset, "deadband: ", NULL);
+					break;
+				case 3:
+					offset = fApplicationTypes   (tvb, tree, offset, "exceeded-limit: ", NULL);
+				default:
+					return offset;
+					break;
+				}
+			}
+        break;
+		case 6:
+			offset = fPropertyValue (tvb,tree,offset);
+		break;
+        case 7: /* buffer-ready */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fObjectIdentifier (tvb, tree, offset); /* buffer-device */
+					break;
+				case 1:
+					offset = fObjectIdentifier (tvb, tree, offset); /* buffer-object */
+					break;
+				case 2:
+					offset = fDateTime (tvb, tree, offset, "previous-notification: ");
+					break;
+				case 3:
+					offset = fDateTime (tvb, tree, offset, "current-notification: ");
+				default:
+					return offset;
+					break;
+				}
+			}
+        break;
+        case 8: /* change-of-life-safety */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fApplicationTypes   (tvb, tree, offset, "new-state: ", BACnetLifeSafetyState);
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "new-mode: ", BACnetLifeSafetyState);
+					break;
+				case 2:
+					offset = fApplicationTypes   (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+				case 3:
+					offset = fLifeSafetyOperationRequest(tvb, tree, offset, "operation-expected: ");
+				default:
+					return offset;
+					break;
+				}
+			}
+        break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fEventParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0: /* change-of-bitstring */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "bitmask: ", NULL);
+					break;
+				case 2:
+					offset = fApplicationTypes   (tvb, tree, offset, "bitstring value: ", BACnetEventTransitionBits);
+					break;
+				default:
+					return offset;
+				}
+			}
+        break;
+		case 1: /* change-of-state */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "value: ", BACnetStatusFlags);
+					break;
+				default:
+					return offset;
+				}
+			}
+			break;
+        case 2: /* change-of-value */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
+					break;
+				case 1: /* don't loop it, it's a CHOICE */
+					switch (fTagNo(tvb, offset)) {
+					case 0:
+						offset = fApplicationTypes   (tvb, tree, offset, "bitmask: ", NULL);
+					break;
+					case 1:
+						offset = fApplicationTypes   (tvb, tree, offset, "referenced Property Incremental: ", NULL);
+					break;
+					default:
+						return offset;
+					}
+				default:
+					return offset;
+				}
+			}
+		break;
+        case 3: /* command-failure */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
+					break;
+				case 1:
+					offset = fDeviceObjectPropertyReference (tvb,tree,offset);
+				default:
+					return offset;
+				}
+			}
+        break;
+        case 4: /* floating-limit */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
+					break;
+				case 1:
+					offset = fDeviceObjectPropertyReference (tvb,tree,offset);
+					break;
+				case 2:
+					offset = fApplicationTypes   (tvb, tree, offset, "low diff limit: ", NULL);
+					break;
+				case 3:
+					offset = fApplicationTypes   (tvb, tree, offset, "high diff limit: ", NULL);
+					break;
+				case 4:
+					offset = fApplicationTypes   (tvb, tree, offset, "deadband: ", NULL);
+					break;
+				default:
+					return offset;
+				}
+			}
+			break;
+        case 5: /* out-of-range */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "low limit: ", NULL);
+					break;
+				case 2:
+					offset = fApplicationTypes   (tvb, tree, offset, "high limit: ", NULL);
+					break;
+				case 3:
+					offset = fApplicationTypes   (tvb, tree, offset, "deadband: ", NULL);
+					break;
+				default:
+					return offset;
+				}
+			}
+        break;
+		case 6:
+			offset = fPropertyValue (tvb,tree,offset);
+		break;
+        case 7: /* buffer-ready */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fUnsignedTag (tvb,tree,offset,"notification threshold");
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "previous notification count: ", NULL);
+					break;
+				default:
+					return offset;
+				}
+			}
+        break;
+        case 8: /* change-of-life-safety */
+			while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+                lastoffset = offset;
+				switch (fTagNo(tvb, offset)) {
+				case 0:
+					offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
+					break;
+				case 1:
+					offset = fApplicationTypes   (tvb, tree, offset, "life safety alarm value: ", BACnetLifeSafetyState);
+					break;
+				case 2:
+					offset = fApplicationTypes   (tvb, tree, offset, "alarm value: ", BACnetLifeSafetyState);
+					break;
+				case 3:
+					offset = fDeviceObjectPropertyReference (tvb, tree, offset);
+					break;
+				default:
+					return offset;
+				}
+			}
+        break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0: /* timestamp */
+			offset = fDateTime (tvb,tree,offset,NULL);
+			break;
+		case 1: /* logDatum: don't loop, it's a CHOICE */
+			switch (fTagNo(tvb, offset)) {
+			case 0:	/* logStatus */
+				offset = fApplicationTypes   (tvb, tree, offset, "log status: ", BACnetLogStatus);
+				break;
+			case 1:
+				offset = fApplicationTypes   (tvb, tree, offset, "boolean-value: ", NULL);
+				break;
+			case 2:
+				offset = fApplicationTypes   (tvb, tree, offset, "real value: ", NULL);
+				break;
+			case 3:
+				offset = fApplicationTypes   (tvb, tree, offset, "enum value: ", NULL);
+				break;
+			case 4:
+				offset = fUnsignedTag   (tvb, tree, offset, "unsigned value: ");
+				break;
+			case 5:
+				offset = fApplicationTypes   (tvb, tree, offset, "signed value: ", NULL);
+				break;
+			case 6:
+				offset = fApplicationTypes   (tvb, tree, offset, "bitstring value: ", NULL);
+				break;
+			case 7:
+				offset = fApplicationTypes   (tvb, tree, offset, "null value: ", NULL);
+				break;
+			case 8:
+				offset = fError (tvb,tree,offset);
+				break;
+			case 9:
+				offset = fApplicationTypes   (tvb, tree, offset, "time change: ", NULL);
+				break;
+			case 10:	/* any Value */
+				offset = fAbstractSyntaxNType   (tvb, tree, offset);
+				break;
+			default:
+				return offset;
+			}
+        break;
+		case 2:
+			offset = fApplicationTypes   (tvb, tree, offset, "status Flags: ", BACnetStatusFlags);
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* ProcessId */
+			offset = fProcessId (tvb,tree,offset);
+			break;
+		case 1: /* initiating ObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 2: /* event ObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 3:	/* time stamp */
+			offset = fApplicationTypes   (tvb, tree, offset, "Time Stamp: ", NULL);
+			break;
+		case 4:	/* notificationClass */
+			offset = fApplicationTypes   (tvb, tree, offset, "Notification Class: ", NULL);
+			break;
+		case 5:	/* Priority */
+			offset = fApplicationTypes   (tvb, tree, offset, "Priority: ", NULL);
+			break;
+		case 6:	/* EventType */
+			offset = fApplicationTypes   (tvb, tree, offset, "Event Type: ", BACnetEventType);
+			break;
+		case 7: /* messageText */
+			offset = fApplicationTypes   (tvb, tree, offset, "message Text: ", NULL);
+			break;
+		case 8:	/* NotifyType */
+			offset = fApplicationTypes   (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
+			break;
+		case 9: /* ackRequired */
+			offset = fApplicationTypes   (tvb, tree, offset, "ack Required: ", NULL);
+			break;
+		case 10: /* fromState */
+			offset = fApplicationTypes   (tvb, tree, offset, "from State: ", BACnetEventState);
+			break;
+		case 11: /* toState */
+			offset = fApplicationTypes   (tvb, tree, offset, "to State: ", BACnetEventState);
+			break;
+		case 12: /* NotificationParameters */
+			offset = fNotificationParameters (tvb, tree, offset);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* ProcessId */
+			offset = fProcessId (tvb,tree,offset);
+			break;
+		case 1: /* initiating ObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 2: /* event ObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 3:	/* time stamp */
+			offset = fApplicationTypes   (tvb, tree, offset, "Time Stamp: ", NULL);
+			break;
+		case 4:	/* notificationClass */
+			offset = fApplicationTypes   (tvb, tree, offset, "Notification Class: ", NULL);
+			break;
+		case 5:	/* Priority */
+			offset = fApplicationTypes   (tvb, tree, offset, "Priority: ", NULL);
+			break;
+		case 6:	/* EventType */
+			offset = fApplicationTypes   (tvb, tree, offset, "Event Type: ", BACnetEventType);
+			break;
+		case 7: /* messageText */
+			offset = fApplicationTypes   (tvb, tree, offset, "message Text: ", NULL);
+			break;
+		case 8:	/* NotifyType */
+			offset = fApplicationTypes   (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
+			break;
+		case 9: /* ackRequired */
+			offset = fApplicationTypes   (tvb, tree, offset, "ack Required: ", NULL);
+			break;
+		case 10: /* fromState */
+			offset = fApplicationTypes   (tvb, tree, offset, "from State: ", BACnetEventState);
+			break;
+		case 11: /* toState */
+			offset = fApplicationTypes   (tvb, tree, offset, "to State: ", BACnetEventState);
+			break;
+		case 12: /* NotificationParameters */
+			offset = fNotificationParameters (tvb, tree, offset);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) {   /* closing Tag */
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* ProcessId */
+			offset = fProcessId (tvb,tree,offset);
+			break;
+		case 1: /* initiating ObjectId */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 2: /* monitored ObjectId */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 3:	/* time remaining */
+			offset = fTimeSpan (tvb, tree, offset, "Time remaining");
+			break;
+		case 4:	/* List of Values */
+			if (((lvt == 6) && class_tag)) { offset++;   /* opening Tag */
+				tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fPropertyValue (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) {   /* closing Tag */
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* subscriberProcessId */
+			offset = fProcessId (tvb,tree,offset);
+			break;
+		case 1: /* initiating ObjectId */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 2: /* monitored ObjectId */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 3:	/* time remaining */
+			offset = fTimeSpan (tvb, tree, offset, "Time remaining");
+			break;
+		case 4:	/* List of Values */
+			if (((lvt == 6) && class_tag)) {  offset++;  /* opening Tag */
+				tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fPropertyValue (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAcknowlegdeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* acknowledgingProcessId */
+			offset = fUnsignedTag (tvb, tree, offset, "acknowledging Process Id: ");
+			break;
+		case 1: /* eventObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 2: /* eventStateAcknowledged */
+			fApplicationTypes   (tvb, tree, offset, "event State Acknowledged: ", BACnetEventState);
+			break;
+		case 3:	/* timeStamp */
+			offset = fTime (tvb, tree, offset, "time Stamp: ");
+			break;
+		case 4:	/* acknowledgementSource */
+			offset = fApplicationTypes   (tvb, tree, offset, "acknowledgement Source: ", NULL);
+			break;
+		case 5:	/* timeOfAcknowledgement */
+			offset = fTime (tvb, tree, offset, "time Of Acknowledgement: ");
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fGetAlarmSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		offset = fObjectIdentifier (tvb, tree, offset);
+		offset = fApplicationTypes   (tvb, tree, offset, "alarm State: ", BACnetEventState);
+		offset = fApplicationTypes   (tvb, tree, offset, "acknowledged Transitions: ", BACnetEventTransitionBits);
+	}
+	return  offset;
+}
+
+static guint
+fGetEnrollmentSummaryRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* acknowledgmentFilter */
+			offset = fApplicationTypes   (tvb, tree, offset, "acknowledgment Filter: ", BACnetAcknowledgementFilter);
+			break;
+		case 1: /* eventObjectId */
+			offset = fRecipientProcess (tvb, tree, offset);
+			break;
+		case 2: /* eventStateFilter */
+			offset = fApplicationTypes   (tvb, tree, offset, "event State Filter: ", BACnetEventStateFilter);
+			break;
+		case 3:	/* eventTypeFilter */
+			offset = fApplicationTypes   (tvb, tree, offset, "event Type Filter: ", BACnetEventType);
+			break;
+		case 4:	/* priorityFilter */
+			offset = fUnsignedTag (tvb, tree, offset, "min Priority: ");
+			offset = fUnsignedTag (tvb, tree, offset, "max Priority: ");
+			break;
+		case 5:	/* notificationClassFilter */
+			offset = fUnsignedTag (tvb, tree, offset, "notification Class Filter: ");
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fGetEnrollmentSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		offset = fObjectIdentifier (tvb, tree, offset);
+		offset = fApplicationTypes   (tvb, tree, offset, "event Type: ", BACnetEventType);
+		offset = fApplicationTypes   (tvb, tree, offset, "event State: ", BACnetEventStateFilter);
+		offset = fUnsignedTag (tvb, tree, offset, "Priority: ");
+		offset = fUnsignedTag (tvb, tree, offset, "notification Class: ");
+	}
+
+	return  offset;
+}
+
+static guint
+fGetEventInformationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* lastReceivedObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+flistOfEventSummaries (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* ObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 1: /* eventState */
+			offset = fApplicationTypes   (tvb, tree, offset, "event State: ", BACnetEventStateFilter);
+			break;
+		case 2: /* acknowledgedTransitions */
+			offset = fApplicationTypes   (tvb, tree, offset, "acknowledged Transitions: ", BACnetEventTransitionBits);
+			break;
+		case 3: /* eventTimeStamps */
+			offset = fTime (tvb, tree, offset, "time Stamp: ");
+			offset = fTime (tvb, tree, offset, "time Stamp: ");
+			offset = fTime (tvb, tree, offset, "time Stamp: ");
+			break;
+		case 4: /* notifyType */
+			offset = fApplicationTypes   (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
+			break;
+		case 5: /* eventEnable */
+			offset = fApplicationTypes   (tvb, tree, offset, "event Enable: ", BACnetEventTransitionBits);
+			break;
+		case 6: /* eventPriorities */
+			offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
+			offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
+			offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fGetEventInformationACK (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* listOfEventSummaries */
+			offset = flistOfEventSummaries (tvb, tree, offset);
+			break;
+		case 1: /* moreEvents */
+			offset = fApplicationTypes   (tvb, tree, offset, "more Events: ", NULL);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAddListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) {   /* closing Tag */
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* ObjectId */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 2: /* propertyArrayIndex */
+			offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		case 3:	/* listOfElements */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fDeleteObjectRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	return fObjectIdentifier (tvb, tree, offset);
+}
+
+static guint
+fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* timeDuration */
+			offset = fUnsignedTag (tvb,tree,offset,"time Duration: ");
+			break;
+		case 1:	/* enable-disable */
+			offset = fApplicationTypes   (tvb, tree, offset, "enable-disable: ", BACnetEnableDisable);
+			break;
+		case 2: /* password */
+			offset = fApplicationTypes   (tvb, tree, offset, "Password: ", NULL);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* reinitializedStateOfDevice */
+			offset = fApplicationTypes   (tvb, tree, offset, "reinitialized State Of Device: ", BACnetReinitializedStateOfDevice);
+			break;
+		case 1: /* password */
+			offset = fApplicationTypes   (tvb, tree, offset, "Password: ", NULL);
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fVtOpenRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+	offset = fApplicationTypes   (tvb, tree, offset, "vtClass: ", BACnetVTClass);
+	return fUnsignedTag (tvb,tree,offset,"local VT Session ID: ");
+}
+
+static guint
+fVtOpenAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+	return offset= fUnsignedTag (tvb,tree,offset,"remote VT Session ID: ");
+}
+
+static guint
+fVtCloseRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		offset= fUnsignedTag (tvb,tree,offset,"remote VT Session ID: ");
+	}
+	return offset;
+}
+
+static guint
+fVtDataRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+	offset= fUnsignedTag (tvb,tree,offset,"VT Session ID: ");
+	offset = fApplicationTypes   (tvb, tree, offset, "VT New Data: ", NULL);
+	return fUnsignedTag (tvb,tree,offset,"VT Data Flag: ");;
+}
+
+static guint
+fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* BOOLEAN */
+			offset = fApplicationTypes   (tvb, tree, offset, "all New Data Accepted: ", NULL);
+			break;
+		case 1:	/* Unsigned OPTIONAL */
+			offset = fUnsignedTag (tvb, tree, offset, "accepted Octet Count: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* Unsigned32 */
+			offset = fUnsignedTag (tvb, tree, offset, "pseudo Random Number: ");
+			break;
+		case 1:	/* expected Invoke ID Unsigned8 OPTIONAL */
+			proto_tree_add_item(tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
+			break;
+		case 2: /* Chararacter String OPTIONAL */
+			offset = fApplicationTypes (tvb, tree, offset, "operator Name: ", NULL);
+			break;
+		case 3:	/* Chararacter String OPTIONAL */
+			offset = fApplicationTypes   (tvb, tree, offset, "operator Password: ", NULL);
+			break;
+		case 4: /* Boolean OPTIONAL */
+			offset = fApplicationTypes   (tvb, tree, offset, "start Encyphered Session: ", NULL);
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAuthenticateAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	return fUnsignedTag (tvb, tree, offset, "modified Random Number: ");
+}
+
+static guint
+fRequestKeyRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+
+	offset = fObjectIdentifier (tvb, tree, offset); /* Requesting Device Identifier */
+	offset = fAddress (tvb, tree, offset);
+	offset = fObjectIdentifier (tvb, tree, offset); /* Remote Device Identifier */
+	return fAddress (tvb, tree, offset);
+}
+
+static guint
+fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+	
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* subscriberProcessId */
+			offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
+			break;
+		case 1: /* monitored ObjectId */
+			offset = fObjectIdentifier (tvb, tree, offset);
+		break;
+		case 2: /* issueConfirmedNotifications */
+			offset = fApplicationTypes   (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
+			break;
+		case 3:	/* life time */
+			offset = fTimeSpan (tvb,tree,offset,"life time");
+			break;
+		case 4: /* monitoredPropertyIdentifier */
+			offset = fApplicationTypes   (tvb, tree, offset, "monitored Property Id: ", NULL);
+			break;
+		case 5: /* covIncrement */
+			offset = fUnsignedTag (tvb, tree, offset, "cov Increment: ");
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fRemoveListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) {   /* closing Tag */
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* ObjectId */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 2: /* propertyArrayIndex */
+			offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		case 3:	/* listOfElements */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+	return offset;
+}
+
+static guint
+fReadPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	proto_tree *subtree = tree;
+    proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* objectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+			break;
+		case 2: /* propertyArrayIndex */
+			offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fReadPropertyAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+    proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) { 
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 2: /* propertyArrayIndex */
+			offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		case 3:	/* propertyValue */
+			if ((lvt == 6) && class_tag) {   offset++;
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+			/*	offset = fPropertyValue (tvb,subtree,offset); */
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fWritePropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+    proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if (((lvt == 7) && class_tag)) { 
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+			break;
+		case 2: /* propertyArrayIndex */
+			offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		case 3:	/* propertyValue */
+			if ((lvt == 6) && class_tag) {   offset++;
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		case 4: /* Priority (only used for write) */
+			offset = fSignedTag (tvb, subtree, offset, "Priority: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* listOfPropertyValues */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fPropertyValue (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fWritePropertyMultipleRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+
+	return fWriteAccessSpecification (tvb, tree, offset);
+}
+
+static guint
+fPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree* subtree = tree;
+	proto_item* tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag, but not for me */
+			return offset;
+		}
+		switch (tag_no) {
+		case 0:	/* PropertyIdentifier */
+			offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 1:	/* propertyArrayIndex */
+			offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	proto_tree* subtree = tree;
+	proto_item* tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		
+        switch (fTagNo(tvb,offset)) {
+		case 0:	/* ObjectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* PropertyIdentifier */
+			offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 2:	/* propertyArrayIndex */
+			offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree* subtree = tree;
+	proto_item* tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+            offset++; /* check it again, Lka */
+			continue;
+		}
+		switch (tag_no) {
+		case 0:	/* ObjectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* PropertyIdentifier */
+			offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 2:	/* propertyArrayIndex */
+			offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		case 3:  /* Value */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fAbstractSyntaxNType   (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		case 4:  /* Priority */
+			offset = fSignedTag (tvb, subtree, offset, "Priority: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+
+static guint
+fDeviceObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	proto_tree* subtree = tree;
+	proto_item* tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		
+        switch (fTagNo(tvb,offset)) {
+		case 0:	/* ObjectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* PropertyIdentifier */
+			offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 2:	/* propertyArrayIndex */
+			offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		case 3:	/* deviceIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fPriorityArray (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint8 i, ar[256];
+
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+	
+	for (i = 1; i <= 16; i++) {
+		
+		sprintf (ar, "%s[%d]: ", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "identifier (%d) not found"), i);
+		offset = fApplicationTypes   (tvb, tree, offset, ar, BACnetBinaryPV);
+	}
+	return offset;
+}
+
+static guint
+fDeviceObjectReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		
+        switch (fTagNo(tvb,offset)) {
+		case 0:	/* deviceIdentifier */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 1:	/* ObjectIdentifier */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fSpecialEvent (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		
+        switch (fTagNo(tvb,offset)) {
+		case 0:	/* calendaryEntry */
+			offset = fCalendaryEntry (tvb, tree, offset);
+			break;
+		case 1:	/* calendarReference */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		case 2:	/* calendarReference */
+			offset = fTimeValue (tvb, tree, offset);
+			break;
+		case 3:	/* eventPriority */
+			offset = fUnsignedTag (tvb, tree, offset, "event priority: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fSelectionCriteria (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		
+		switch (fTagNo(tvb,offset)) {
+		case 0:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 1:	/* propertyArrayIndex */
+			offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+			break;
+		case 2: /* relationSpecifier */
+			offset = fApplicationTypes   (tvb, subtree, offset, "relation Specifier: ", BACnetRelationSpecifier);
+			break;
+		case 3: /* comparisonValue */
+			offset = fAbstractSyntaxNType   (tvb, subtree, offset);
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* selectionLogic */
+			offset = fApplicationTypes   (tvb, subtree, offset, "selection Logic: ", BACnetSelectionLogic);
+			break;
+		case 1:	/* listOfSelectionCriteria */
+			if ((lvt == 6) && class_tag) {  offset++; /* opening Tag */
+				offset = fSelectionCriteria (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+
+static guint
+fReadPropertyConditionalRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectSelectionCriteria */
+			offset = fObjectSelectionCriteria (tvb, subtree, offset);
+			break;
+		case 1:	/* listOfPropertyReferences */
+			if ((lvt == 6) && class_tag) {  offset++; /* opening Tag */
+				offset = fPropertyReference (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fReadAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectIdentifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* listOfPropertyReferences */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fPropertyReference (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no;
+	guint8 class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectSpecifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* list of Results */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				break;
+			}
+			FAULT;
+			break;
+		case 2:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_list);
+			break;
+		case 3:	/* propertyArrayIndex Optional */
+			offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
+			break;
+		case 4:	/* propertyValue */
+			if ((lvt == 6) && class_tag) {  offset++; /* opening Tag */
+				offset = fAbstractSyntaxNType (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		case 5:	/* propertyAccessError */
+			if ((lvt == 6) && class_tag) {  offset++; /* opening Tag */
+				/* Error Code follows */
+				offset = fApplicationTypes   (tvb, subtree, offset, "error Class: ", BACnetErrorClass);
+				offset = fApplicationTypes   (tvb, subtree, offset, "error Code: ", BACnetErrorCode);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+
+static guint
+fReadPropertyConditionalAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	/* listOfReadAccessResults */
+	return fReadAccessResult (tvb, tree, offset);
+}
+
+
+static guint
+fObjectSpecifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* objectType */
+			proto_tree_add_item(tree, hf_bacapp_tag_initiatingObjectType, tvb, offset++, 1, TRUE);
+			break;
+		case 1:	/* objectIdentifier */
+			offset = fObjectIdentifier (tvb, tree, offset);
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fCreateObjectRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+
+	while ((offset < tvb_reported_length(tvb)) && (offset > lastoffset)) {  /* exit loop if nothing happens inside */
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectSpecifier */
+			offset = fObjectSpecifier (tvb, subtree, offset);
+			break;
+		case 1:	/* propertyValue */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fPropertyValue (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	return fObjectIdentifier (tvb, tree, offset);
+}
+
+static guint
+fReadRangeRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectSpecifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 2:	/* propertyArrayIndex Optional */
+			offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
+			break;
+		case 3:	/* range byPosition */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fApplicationTypes   (tvb, subtree, offset, "reference Index: ", NULL);
+				offset = fApplicationTypes   (tvb, subtree, offset, "reference Count: ", NULL);
+				break;
+			}
+			FAULT;
+			break;
+		case 4:	/* range byTime */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fApplicationTypes   (tvb, subtree, offset, "reference Time: ", NULL);
+				offset = fApplicationTypes   (tvb, subtree, offset, "reference Count: ", NULL);
+				break;
+			}
+			FAULT;
+			break;
+		case 5:	/* range timeRange */
+			if ((lvt == 6) && class_tag) { offset++;  /* opening Tag */
+				offset = fApplicationTypes   (tvb, subtree, offset, "beginning Time: ", NULL);
+				offset = fApplicationTypes   (tvb, subtree, offset, "ending Time: ", NULL);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fReadRangeAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			subtree = tree;
+			offset++;
+			continue;
+		}
+	
+		switch (tag_no) {
+		case 0:	/* objectSpecifier */
+			offset = fObjectIdentifier (tvb, subtree, offset);
+			break;
+		case 1:	/* propertyIdentifier */
+			offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+			subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+			break;
+		case 2:	/* propertyArrayIndex Optional */
+			offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
+			break;
+		case 3:	/* resultFlags */
+			offset = fApplicationTypes   (tvb, subtree, offset, "result Flags: ", BACnetResultFlags);
+			break;
+		case 4:	/* itemCount */
+			offset = fUnsignedTag (tvb, subtree, offset, "item Count: ");
+			break;
+		case 5:	/* itemData */
+			if ((lvt == 6) && class_tag) {  offset++; /* opening Tag */
+				offset = fAbstractSyntaxNType   (tvb, subtree, offset);
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAtomicReadFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	offset = fObjectIdentifier (tvb, tree, offset);
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+		if ((lvt == 7) && class_tag) {   /* closing Tag */
+			offset++;
+			subtree = tree;
+			continue;
+		}
+
+		switch (tag_no) {
+		case 0:	/* streamAccess */
+			if ((lvt == 6) && class_tag) {   /* opening Tag */
+				tt = proto_tree_add_text(subtree, tvb, offset++, 1, "stream Access");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
+				offset = fUnsignedTag (tvb, subtree, offset, "requestet Octet Count: ");
+				break;
+			}
+			FAULT;
+			break;
+		case 1:	/* recordAccess */
+			if ((lvt == 6) && class_tag) {   /* opening Tag */
+				tt = proto_tree_add_text(subtree, tvb, offset++, 1, "record Access");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fSignedTag (tvb, subtree, offset, "File Start Record: ");
+				offset = fUnsignedTag (tvb, subtree, offset, "requestet Record Count: ");
+				break;
+			}
+			FAULT;
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) {	/* Segment of an Request */
+		if (bacapp_flags & 0x04) { /* More Flag is set */
+			offset = fOctetString (tvb, tree, offset, "file Data: ", 0);
+		} else {
+			offset = fOctetString (tvb, tree, offset, "file Data: ", tvb_reported_length(tvb) - offset - 1);
+			fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if ((lvt == 7) && class_tag) {   /* closing Tag */
+				offset++;
+			}
+		}
+	} else {
+		offset = fObjectIdentifier (tvb, tree, offset); /* file Identifier */
+
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+		switch (tag_no) {
+		case 0:	/* streamAccess */
+			if ((lvt == 6) && class_tag) {   /* opening Tag */
+				tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
+				offset = fApplicationTypes   (tvb, subtree, offset, "file Data: ", NULL);
+			}
+			if (bacapp_flags && 0x04) { /* More Flag is set */
+				break;
+			}
+			fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if (((lvt == 7) && class_tag)) {   /* closing Tag */
+				offset++;
+				subtree = tree;
+			}
+			break;
+		case 1:	/* recordAccess */
+			if ((lvt == 6) && class_tag) {   /* opening Tag */
+				tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fSignedTag (tvb, subtree, offset, "file Start Record: ");
+				offset = fUnsignedTag (tvb, subtree, offset, "Record Count: ");
+				offset = fApplicationTypes   (tvb, subtree, offset, "file Data: ", NULL);
+			}
+			if (bacapp_flags && 0x04) { /* More Flag is set */
+				break;
+			}
+			fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if (((lvt == 7) && class_tag)) {   /* closing Tag */
+				offset++;
+				subtree = tree;
+			}
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	switch (fTagNo(tvb, offset)) {
+	case 0:	/* streamAccess */
+		offset = fSignedTag (tvb, tree, offset, "File Start Position: ");
+		break;
+	case 1:	/* recordAccess */
+		offset = fSignedTag (tvb, tree, offset, "File Start Record: ");
+		break;
+	default:
+		return offset;
+	}
+	return offset;
+}
+
+static guint
+fAtomicReadFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint8 tag_no, class_tag;
+	guint32 lvt;
+	proto_tree *subtree = tree;
+	proto_item *tt;
+
+	fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+	if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) {	/* Segment of an Request */
+		if (bacapp_flags & 0x04) { /* More Flag is set */
+			offset = fOctetString (tvb, tree, offset, "File Data: ", 0);
+		} else {
+			offset = fOctetString (tvb, tree, offset, "File Data: ", tvb_reported_length(tvb)-offset-1);
+			fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if ((lvt == 7) && class_tag) {   /* closing Tag */
+				offset++;
+			}
+		}
+	} else {
+		offset = fApplicationTypes   (tvb, subtree, offset, "End Of File: ", NULL);
+
+		fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+		switch (tag_no) {
+		case 0:	/* streamAccess */
+			if ((lvt == 6) && class_tag) {   /* opening Tag */
+				tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
+				subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+				offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
+				offset = fApplicationTypes   (tvb, subtree, offset, "file Data: ", NULL);
+			}
+			if (bacapp_flags && 0x04) { /* More Flag is set */
+				break;
+			}
+			fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if ((lvt == 7) && class_tag) {   /* closing Tag */
+				offset++;
+				subtree = tree;
+			}
+			break;
+		case 1:	/* recordAccess */
+			if ((lvt == 6) && class_tag) {   /* opening Tag */
+				proto_tree_add_text(tree, tvb, offset++, 1, "stream Access {");
+				offset = fSignedTag (tvb, subtree, offset, "File Start Record: ");
+				offset = fUnsignedTag (tvb, subtree, offset, "returned Record Count: ");
+				offset = fApplicationTypes   (tvb, subtree, offset, "Data: ", NULL);
+			}
+			if (bacapp_flags && 0x04) { /* More Flag is set */
+				break;
+			}
+			fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+			if ((lvt == 7) && class_tag) {   /* closing Tag */
+				offset++;
+				subtree = tree;
+			}
+		break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fReadPropertyMultipleRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+	return fReadAccessSpecification (tvb,subtree,offset);
+}
+
+static guint
+fReadPropertyMultipleAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	return fReadAccessResult (tvb,tree,offset);
+}
+
+static guint
+fConfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+
+	switch (service_choice) {
+	case 0:	/* acknowledgeAlarm */
+		offset = fAcknowlegdeAlarmRequest (tvb, tree, offset);
+		break;
+	case 1: /* confirmedCOVNotification */
+		offset = fConfirmedCOVNotificationRequest (tvb, tree, offset);
+		break;
+	case 2: /* confirmedEventNotification */
+		offset = fConfirmedEventNotificationRequest (tvb, tree, offset);
+		break;
+	case 3: /* confirmedGetAlarmSummary conveys no parameters */
+		break;
+	case 4: /* getEnrollmentSummaryRequest */
+		offset = fGetEnrollmentSummaryRequest (tvb, tree, offset);
+		break;
+	case 5: /* subscribeCOVRequest */
+		offset = fSubscribeCOVRequest(tvb, tree, offset);
+		break;
+	case 6: /* atomicReadFile-Request */
+		offset = fAtomicReadFileRequest(tvb, tree, offset);
+		break;
+	case 7: /* atomicWriteFile-Request */
+		offset = fAtomicWriteFileRequest(tvb, tree, offset);
+		break;
+	case 8: /* AddListElement-Request */
+		offset = fAddListElementRequest(tvb, tree, offset);
+		break;
+	case 9: /* removeListElement-Request */
+		offset = fRemoveListElementRequest(tvb, tree, offset);
+		break;
+	case 10: /* createObjectRequest */
+		offset = fCreateObjectRequest(tvb, tree, offset);
+		break;
+	case 11: /* deleteObject */
+		offset = fDeleteObjectRequest(tvb, tree, offset);
+		break;
+	case 12:
+		offset = fReadPropertyRequest(tvb, tree, offset);
+		break;
+	case 13:
+		offset = fReadPropertyConditionalRequest(tvb, tree, offset);
+		break;
+	case 14:
+		offset = fReadPropertyMultipleRequest(tvb, tree, offset);
+		break;
+	case 15:
+		offset = fWritePropertyRequest(tvb, tree, offset);
+		break;
+	case 16:
+		offset = fWritePropertyMultipleRequest(tvb, tree, offset);
+		break;
+	case 17:
+		offset = fDeviceCommunicationControlRequest(tvb, tree, offset);
+		break;
+	case 18:
+		offset = fConfirmedPrivateTransferRequest(tvb, tree, offset);
+		break;
+	case 19:
+		offset = fConfirmedTextMessageRequest(tvb, tree, offset);
+		break;
+	case 20:
+		offset = fReinitializeDeviceRequest(tvb, tree, offset);
+		break;
+	case 21:
+		offset = fVtOpenRequest(tvb, tree, offset);
+		break;
+	case 22:
+		offset = fVtCloseRequest (tvb, tree, offset);
+		break;
+	case 23:
+		offset = fVtDataRequest (tvb, tree, offset);
+		break;
+	case 24:
+		offset = fAuthenticateRequest (tvb, tree, offset);
+		break;
+	case 25:
+		offset = fRequestKeyRequest (tvb, tree, offset);
+		break;
+	case 26:
+		offset = fReadRangeRequest (tvb, tree, offset);
+		break;
+	case 27:
+		offset = fLifeSafetyOperationRequest(tvb, tree, offset, NULL);
+		break;
+	case 28:
+		offset = fSubscribeCOVPropertyRequest(tvb, tree, offset);
+		break;
+	case 29:
+		offset = fGetEventInformationRequest (tvb, tree, offset);
+		break;
+	default:
+		return offset;
+		break;
+	}
+	return offset;
+}
+
+static guint
+fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+
+	switch (service_choice) {
+	case 3: /* confirmedEventNotificationAck */
+		offset = fGetAlarmSummaryAck (tvb, tree, offset);
+		break;
+	case 4: /* getEnrollmentSummaryAck */
+		offset = fGetEnrollmentSummaryAck (tvb, tree, offset);
+		break;
+	case 6: /* atomicReadFile */
+		offset = fAtomicReadFileAck (tvb, tree, offset);
+		break;
+	case 7: /* atomicReadFileAck */
+		offset = fAtomicWriteFileAck (tvb, tree, offset);
+		break;
+	case 10: /* createObject */
+		offset = fCreateObjectAck (tvb, tree, offset);
+		break;
+	case 12:
+		offset = fReadPropertyAck (tvb, tree, offset);
+		break;
+	case 13:
+		offset = fReadPropertyConditionalAck (tvb, tree, offset);
+		break;
+	case 14:
+		offset = fReadPropertyMultipleAck (tvb, tree, offset);
+		break;
+	case 18:
+		offset = fConfirmedPrivateTransferAck(tvb, tree, offset);
+		break;
+	case 21:
+		offset = fVtOpenAck (tvb, tree, offset);
+		break;
+	case 23:
+		offset = fVtDataAck (tvb, tree, offset);
+		break;
+	case 24:
+		offset = fAuthenticateAck (tvb, tree, offset);
+		break;
+	case 26:
+		offset = fReadRangeAck (tvb, tree, offset);
+		break;
+	case 29:
+		offset = fGetEventInformationACK (tvb, tree, offset);
+		break;
+	default:
+		return offset;
+	}
+	return offset;
+}
+
+static guint
+fIAmRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	guint8 tmp, tag_no, class_tag, i;
+	guint32 lvt, val = 0;
+
+	/* BACnetObjectIdentifier */
+	offset = fApplicationTypes   (tvb, tree, offset, "BACnet Object Identifier: ", NULL);
+
+	/* MaxAPDULengthAccepted */
+	offset = fApplicationTypes   (tvb, tree, offset, "Maximum ADPU Length accepted: ", NULL);
+
+	/* segmentationSupported */
+	fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+	offset++;	/* set offset according to enhancements.... */
+	for (i = 0; i < min(lvt, 4); i++) {
+		tmp = tvb_get_guint8(tvb, offset+i);
+		val = (val << 8) + tmp;
+	}
+	proto_tree_add_text(tree, tvb, offset, 1, "segmentation Supported: %s", val_to_str(val, BACnetSegmentation, "segmentation (%d) not found"));
+	offset+=lvt;
+
+	/* vendor ID */
+	return fUnsignedTag (tvb, tree, offset, "vendor ID: ");
+}
+
+static guint
+fIHaveRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	/* BACnetDeviceIdentifier */
+	offset = fApplicationTypes   (tvb, tree, offset, "Device Identifier: ", NULL);
+
+	/* BACnetObjectIdentifier */
+	offset = fApplicationTypes   (tvb, tree, offset, "Object Identifier: ", NULL);
+
+	/* ObjectName */
+	return fApplicationTypes   (tvb, tree, offset, "Object Name: ", NULL);
+
+}
+
+static guint
+fWhoIsRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* DeviceInstanceRangeLowLimit Optional */
+			offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range Low Limit: ");
+			break;
+		case 1:	/* DeviceInstanceRangeHighLimit Optional but required if DeviceInstanceRangeLowLimit is there */
+			offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range High Limit: ");
+			break;
+		default:
+			return offset;
+			break;
+		}
+	}
+ 	return offset;
+}
+
+static guint
+fUnconfirmedServiceRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
+{
+	if (offset >= tvb_reported_length(tvb))
+		return offset;
+	
+	switch (service_choice) {
+	case 0:	/* I-Am-Request */
+		offset = fIAmRequest  (tvb, tree, offset);
+		break;
+	case 1: /* i-Have Request */
+		offset = fIHaveRequest  (tvb, tree, offset);
+	break;
+	case 2: /* unconfirmedCOVNotification */
+		offset = fUnconfirmedCOVNotificationRequest (tvb, tree, offset);
+		break;
+	case 3: /* unconfirmedEventNotification */
+		offset = fUnconfirmedEventNotificationRequest (tvb, tree, offset);
+		break;
+	case 4: /* unconfirmedPrivateTransfer */
+		offset = fUnconfirmedPrivateTransferRequest(tvb, tree, offset);
+		break;
+	case 5: /* unconfirmedTextMessage */
+		offset = fUnconfirmedTextMessageRequest(tvb, tree, offset);
+		break;
+	case 6: /* timeSynchronization */
+		offset = fTimeSynchronizationRequest  (tvb, tree, offset);
+		break;
+	case 7: /* who-Has */
+		offset = fWhoHas (tvb, tree, offset);
+		break;
+	case 8: /* who-Is */
+		offset = fWhoIsRequest  (tvb, tree, offset);
+		break;
+	case 9: /* utcTimeSynchronization */
+		offset = fUTCTimeSynchronizationRequest  (tvb, tree, offset);
+		break;
+	default:
+		break;
+	}
+	return offset;
+}
+
+static guint
+fConfirmedRequestPDU(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, BACnetConfirmedServiceChoice, "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);
+		offset = fConfirmedServiceRequest (tvb, bacapp_tree_tag, offset, tmp);
+	}
+	return offset;
+}
+
+static guint
+fUnconfirmedRequestPDU(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);
+		offset = fUnconfirmedServiceRequest  (tvb, bacapp_tree_tag, offset, tmp);
+	}
+	return offset;
+}
+
+static guint
+fSimpleAckPDU(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, BACnetConfirmedServiceChoice, "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);
+	}
+	return offset;
+}
+
+static guint
+fComplexAckPDU(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, BACnetConfirmedServiceChoice, "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, 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);
+		offset = fConfirmedServiceAck (tvb, bacapp_tree_tag, offset, tmp);
+	}
+	return offset;
+}
+
+
+static guint
+fSegmentAckPDU(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);
 
-		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_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);
 	}
-	next_tvb = tvb_new_subset(tvb,offset,-1,-1);
-	call_dissector(data_handle,next_tvb, pinfo, tree);
+	return offset;
 }
 
+static guint
+fConfirmedPrivateTransferError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
 
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* errorType */
+			offset = fError (tvb,tree,offset);
+			break;
+		case 1:	/* vendorID */
+			offset = fUnsignedTag (tvb,tree,offset,"vendor ID: ");
+			break;
+		case 2:	/* serviceNumber */
+			offset = fUnsignedTag (tvb,tree,offset,"service Number: ");
+			break;
+        case 3: /* errorParameters */
+            offset = fAbstractSyntaxNType   (tvb, tree, offset);
+            break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fCreateObjectError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* errorType */
+			offset = fError (tvb,tree,offset);
+			break;
+		case 1:	/* firstFailedElementNumber */
+			offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* errorType */
+			offset = fError (tvb,tree,offset);
+			break;
+		case 1:	/* firstFailedElementNumber */
+			offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fVTSession(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+	if (offset < tvb_reported_length(tvb)) {	/* don't loop */
+		offset = fUnsignedTag (tvb,tree,offset, "local-VTSessionID: ");
+		offset = fUnsignedTag (tvb,tree,offset, "remote-VTSessionID: ");
+		offset = fAddress (tvb,tree,offset);
+	}
+	return offset;
+}
+
+static guint
+fVTCloseError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* errorType */
+			offset = fError (tvb,tree,offset);
+			break;
+		case 1:	/* listOfVTSessionIdentifiers */
+			offset = fUnsignedTag (tvb,tree,offset,"VT SessionID: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fWritePropertyMultipleError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    guint lastoffset = 0;
+
+	while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */ 
+        lastoffset = offset;
+		switch (fTagNo(tvb, offset)) {
+		case 0:	/* errorType */
+			offset = fError (tvb,tree,offset);
+			break;
+		case 1:	/* firstFailedWriteAttempt */
+			offset = fUnsignedTag (tvb,tree,offset,"first failed write attempt: ");
+			break;
+		default:
+			return offset;
+		}
+	}
+	return offset;
+}
+
+static guint
+fError (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+    offset = fApplicationTypes   (tvb, tree, offset, "error Class: ", BACnetErrorClass);
+    return fApplicationTypes   (tvb, tree, offset, "error Code: ", BACnetErrorCode);
+}
+
+static guint
+fBACnetError (tvbuff_t *tvb, proto_tree *tree, guint offset, guint service)
+{
+    switch (service) {
+    case 8:  /* no break here !!!! */
+    case 9:
+        offset = fChangeListError (tvb, tree, offset);
+        break;
+    case 10:
+        offset = fCreateObjectError (tvb,tree,offset);
+        break;
+    case 16:
+        offset = fWritePropertyMultipleError (tvb,tree,offset);
+        break;
+    case 18:
+        offset = fConfirmedPrivateTransferError (tvb,tree,offset);
+    case 22:
+        offset = fVTCloseError (tvb,tree,offset);
+    default:
+        return fError (tvb, tree, offset);
+        break;
+    }
+    return offset;
+}
+
+static guint
+fErrorPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{	/* BACnet-Error-PDU */
+	/* ASHRAE 135-2001 20.1.7 */
+
+	proto_item *tc, *ti, *tt;
+	proto_tree *bacapp_tree_control, *bacapp_tree, *bacapp_tree_tag;
+    guint8 tmp;
+
+	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);
+		tmp = tvb_get_guint8(tvb, offset);
+		tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+			offset++, 1, TRUE);
+		/* Error Handling follows... */
+		bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
+		offset = fBACnetError (tvb, bacapp_tree_tag, offset, tmp);
+	}
+	return offset;
+}
+
+static guint
+fRejectPDU(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_BACnetRejectReason, tvb,
+			offset++, 1, TRUE);
+	}
+	return offset;
+}
+
+static guint
+fAbortPDU(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_BACnetAbortReason, tvb,
+			offset++, 1, TRUE);
+	}
+	return offset;
+}
+
 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, BACnetTypeName, "#### unknown APDU ##### "));
+
+	/* ASHRAE 135-2001 20.1.1 */
+	switch (bacapp_type) {
+	case 0:	/* BACnet-Confirmed-Service-Request */
+		offset = fConfirmedRequestPDU(tvb, pinfo, tree, offset);
+		break;
+	case 1:	/* BACnet-Unconfirmed-Request-PDU */
+		offset = fUnconfirmedRequestPDU(tvb, pinfo, tree, offset);
+		break;
+	case 2:	/* BACnet-Simple-Ack-PDU */
+		offset = fSimpleAckPDU(tvb, pinfo, tree, offset);
+		break;
+	case 3:	/* BACnet-Complex-Ack-PDU */
+		offset = fComplexAckPDU(tvb, pinfo, tree, offset);
+		break;
+	case 4:	/* BACnet-SegmentAck-PDU */
+		offset = fSegmentAckPDU(tvb, tree, offset);
+		break;
+	case 5:	/* BACnet-Error-PDU */
+		offset = fErrorPDU(tvb, tree, offset);
+		break;
+	case 6:	/* BACnet-Reject-PDU */
+		offset = fRejectPDU(tvb, tree, offset);
+		break;
+	case 7:	/* BACnet-Abort-PDU */
+		offset = fAbortPDU(tvb, tree, offset);
+		break;
+	}
+
+	next_tvb = tvb_new_subset(tvb,offset,-1,tvb_reported_length(tvb) - 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 }
+			{ "APDU Type",           "bacapp.type",
+			FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, "APDU Type", HFILL }
 		},
+		{ &hf_bacapp_SEG,
+			{ "SEG",           "bacapp.SEG",
+			FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, "Segmented Requests", HFILL }
+		},
+		{ &hf_bacapp_MOR,
+			{ "MOR",           "bacapp.MOR",
+			FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL }
+		},
+		{ &hf_bacapp_SA,
+			{ "SA",           "bacapp.SA",
+			FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL }
+		},
+		{ &hf_bacapp_max_adpu_size,
+			{ "Size of Maximum ADPU accepted",           "bacapp.max_adpu_size",
+			FT_UINT8, BASE_DEC, VALS(BACnetMaxAPDULengthAccepted), 0x0f, "Size of Maximum ADPU accepted", HFILL }
+		},
+		{ &hf_bacapp_response_segments,
+			{ "Max Response Segments accepted",           "bacapp.response_segments",
+			FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0xe0, "Max Response Segments accepted", HFILL }
+		},
+		{ &hf_bacapp_objectType,
+			{ "Object Type",           "bacapp.objectType",
+			FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, "Object Type", HFILL }
+		},
+		{ &hf_bacapp_instanceNumber,
+			{ "Instance Number",           "bacapp.instance_number",
+			FT_UINT32, BASE_DEC, NULL, 0x003fffff, "Instance Number", HFILL }
+		},
+		{ &hf_bacapp_invoke_id,
+			{ "Invoke ID",           "bacapp.invoke_id",
+			FT_UINT8, BASE_HEX, NULL, 0, "Invoke ID", HFILL }
+		},
+		{ &hf_bacapp_sequence_number,
+			{ "Sequence Number",           "bacapp.sequence_number",
+			FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL }
+		},
+		{ &hf_bacapp_window_size,
+			{ "Proposed Window Size",           "bacapp.window_size",
+			FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL }
+		},
+		{ &hf_bacapp_service,
+			{ "Service Choice",           "bacapp.confirmed_service",
+			FT_UINT8, BASE_DEC, VALS(BACnetConfirmedServiceChoice), 0x00, "Service Choice", HFILL }
+		},
+		{ &hf_bacapp_uservice,
+			{ "Unconfirmed Service Choice",           "bacapp.unconfirmed_service",
+			FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, "Unconfirmed Service Choice", HFILL }
+		},
+		{ &hf_bacapp_NAK,
+			{ "NAK",           "bacapp.NAK",
+			FT_BOOLEAN, 8, NULL, 0x02, "negativ ACK", HFILL }
+		},
+		{ &hf_bacapp_SRV,
+			{ "SRV",           "bacapp.SRV",
+			FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL }
+		},
+		{ &hf_BACnetRejectReason,
+			{ "Reject Reason",           "bacapp.reject_reason",
+			FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, "Reject Reason", HFILL }
+		},
+		{ &hf_BACnetAbortReason,
+			{ "Abort Reason",           "bacapp.abort_reason",
+			FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 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_BACnetTagNumber,
+			{ "Tag Number",           "bacapp.tag_number",
+			FT_UINT8, BASE_DEC, VALS(BACnetTagNumber), 0xF0, "Tag Number", HFILL }
+		},
+		{ &hf_BACnetTagClass,
+			{ "Class",           "bacapp.class",
+			FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, "Class", HFILL }
+		},
+		{ &hf_bacapp_tag_lvt,
+			{ "Length Value Type",           "bacapp.LVT",
+			FT_UINT8, BASE_DEC, NULL, 0x07, "Length Value Type", HFILL }
+		},
+		{ &hf_bacapp_tag_ProcessId,
+			{ "ProcessIdentifier",           "bacapp.processId",
+			FT_UINT32, BASE_DEC, NULL, 0, "Process Identifier", HFILL }
+		},
+		{ &hf_bacapp_tag_initiatingObjectType,
+			{ "ObjectType",           "bacapp.objectType",
+			FT_UINT16, BASE_DEC, VALS(BACnetObjectType), 0x00, "Object Type", HFILL }
+		},
 	};
 	static gint *ett[] = {
 		&ett_bacapp,
+		&ett_bacapp_control,
+		&ett_bacapp_tag,
+		&ett_bacapp_list,
+		&ett_bacapp_value,
 	};
 	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