X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=epan%2Fdissectors%2Fpacket-bacapp.c;h=debdeca4a7d528508153dbe84e6cc5cfe4ab132c;hb=0ff5638f37a1de5d061106b37930c6767bc445de;hp=0ae3eb2a4bb7a5bd4f67c8c4b782e4a906b8e24f;hpb=02821ce8e5a6e0e21b34b440c8364f7e4cdc7bc4;p=metze%2Fwireshark%2Fwip.git diff --git a/epan/dissectors/packet-bacapp.c b/epan/dissectors/packet-bacapp.c index 0ae3eb2a4b..debdeca4a7 100644 --- a/epan/dissectors/packet-bacapp.c +++ b/epan/dissectors/packet-bacapp.c @@ -1,13 +1,13 @@ /* packet-bacapp.c * Routines for BACnet (APDU) dissection - * Copyright 2001, Hartmut Mueller , FH Dortmund - * Enhanced by Steve Karg, 2005, , Atlanta - * Enhanced by Herbert Lischka, 2005, , Berlin + * Copyright 2001, Hartmut Mueller , FH Dortmund + * Enhanced by Steve Karg, 2005, , Atlanta + * Enhanced by Herbert Lischka, 2005, , Berlin * * $Id$ * - * Ethereal - Network traffic analyzer - * By Gerald Combs + * Wireshark - Network traffic analyzer + * By Gerald Combs * Copyright 1998 Gerald Combs * * Copied from README.developer,v 1.23 @@ -27,11 +27,2146 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "packet-bacapp.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#include +#include +#include + +/* formerly bacapp.h contains definitions and forward declarations */ + +#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 + +/* BACnet PDU Types */ +#define BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST 0 +#define BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST 1 +#define BACAPP_TYPE_SIMPLE_ACK 2 +#define BACAPP_TYPE_COMPLEX_ACK 3 +#define BACAPP_TYPE_SEGMENT_ACK 4 +#define BACAPP_TYPE_ERROR 5 +#define BACAPP_TYPE_REJECT 6 +#define BACAPP_TYPE_ABORT 7 +#define MAX_BACAPP_TYPE 8 + +#define BACAPP_SEGMENTED_REQUEST 0x08 +#define BACAPP_MORE_SEGMENTS 0x04 +#define BACAPP_SEGMENTED_RESPONSE 0x02 +#define BACAPP_SEGMENT_NAK 0x02 +#define BACAPP_SENT_BY 0x01 + + +/** + * 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 + **/ +static 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); + +/** + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @param ack - indocates whether working on request or ack + * @param svc - output variable to return service choice + * @param tt - output varable to return service choice item + * @return modified offset + */ +static guint +fStartConfirmed(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 ack, + gint *svc, proto_item **tt); + +/** + * 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fSegmentAckPDU(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fErrorPDU(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fRejectPDU(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fAbortPDU(tvbuff_t *tvb, packet_info *pinfo, 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, const gchar *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, const gchar *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, const gchar *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, const gchar *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, const gchar *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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fObjectIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * BACnet-Confirmed-Service-Request ::= CHOICE { + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @param service_choice + * @return offset + */ +static guint +fConfirmedServiceRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice); + +/** + * BACnet-Confirmed-Service-ACK ::= CHOICE { + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @param service_choice + * @return offset + */ +static guint +fConfirmedServiceAck (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fAcknowledgeAlarmRequest (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fConfirmedCOVNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fConfirmedEventNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * GetAlarmSummary-ACK ::= SEQUENCE OF SEQUENCE { + * objectIdentifier BACnetObjectIdentifer, + * alarmState BACnetEventState, + * acknowledgedTransitions BACnetEventTransitionBits + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fGetAlarmSummaryAck (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fGetEnrollmentSummaryRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * GetEnrollmentSummary-ACK ::= SEQUENCE OF SEQUENCE { + * objectIdentifier BACnetObjectIdentifer, + * eventType BACnetEventType, + * eventState BACnetEventState, + * priority Unsigned8, + * notificationClass Unsigned OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fGetEnrollmentSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * GetEventInformation-Request ::= SEQUENCE { + * lastReceivedObjectIdentifier [0] BACnetObjectIdentifer + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fGetEventInformationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * GetEventInformation-ACK ::= SEQUENCE { + * listOfEventSummaries [0] listOfEventSummaries, + * moreEvents [1] BOOLEAN + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fGetEventInformationACK (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * LifeSafetyOperation-Request ::= SEQUENCE { + * requestingProcessIdentifier [0] Unsigned32 + * requestingSource [1] CharacterString + * request [2] BACnetLifeSafetyOperation + * objectIdentifier [3] BACnetObjectIdentifier OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fLifeSafetyOperationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); + +/** + * SubscribeCOV-Request ::= SEQUENCE { + * subscriberProcessIdentifier [0] Unsigned32 + * monitoredObjectIdentifier [1] BACnetObjectIdentifier + * issueConfirmedNotifications [2] BOOLEAN OPTIONAL + * lifetime [3] Unsigned OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @param label + * @param src + * @return modified offset + */ +static guint +fSubscribeCOVRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fSubscribeCOVPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fAtomicReadFileRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fAtomicReadFileAck (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fAtomicWriteFileRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fAddListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * CreateObject-Request ::= SEQUENCE { + * objectSpecifier [0] ObjectSpecifier, + * listOfInitialValues [1] SEQUENCE OF BACnetPropertyValue OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fCreateObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset); + +/** + * CreateObject-Request ::= BACnetObjectIdentifier + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fCreateObjectAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * DeleteObject-Request ::= SEQUENCE { + * ObjectIdentifier BACnetObjectIdentifer + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fDeleteObjectRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fReadPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fReadPropertyAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * ReadPropertyConditional-Request ::= SEQUENCE { + * objectSelectionCriteria [0] objectSelectionCriteria, + * listOfPropertyReferences [1] SEQUENCE OF BACnetPropertyReference OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fReadPropertyConditionalRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset); + +/** + * ReadPropertyConditional-ACK ::= SEQUENCE { + * listOfPReadAccessResults SEQUENCE OF ReadAccessResult OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fReadPropertyConditionalAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * ReadPropertyMultiple-Request ::= SEQUENCE { + * listOfReadAccessSpecs SEQUENCE OF ReadAccessSpecification + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return offset modified + */ +static guint +fReadPropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset); + +/** + * ReadPropertyMultiple-Ack ::= SEQUENCE { + * listOfReadAccessResults SEQUENCE OF ReadAccessResult + * } + * @param tvb + * @parma pinfo + * @param tree + * @param offset + * @return offset modified + */ +static guint +fReadPropertyMultipleAck (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fReadRangeRequest (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fReadRangeAck (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fRemoveListElementRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fWritePropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * WritePropertyMultiple-Request ::= SEQUENCE { + * listOfWriteAccessSpecifications SEQUENCE OF WriteAccessSpecification + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fWritePropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fConfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * ConfirmedPrivateTransfer-ACK ::= SEQUENCE { + * vendorID [0] Unsigned, + * serviceNumber [1] Unsigned, + * resultBlock [2] ABSTRACT-SYNTAX.&Type OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fConfirmedPrivateTransferAck(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fConfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fVtOpenRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * VTOpen-ACK ::= SEQUENCE { + * remoteVTSessionIdentifier Unsigned8 + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fVtOpenAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * VTClose-Request ::= SEQUENCE { + * listOfRemoteVTSessionIdentifiers SEQUENCE OF Unsigned8 + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fVtCloseRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * VTData-Request ::= SEQUENCE { + * vtSessionIdentifier Unsigned8, + * vtNewData OCTET STRING, + * vtDataFlag Unsigned (0..1) + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fVtDataRequest (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fAuthenticateAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * RequestKey-Request ::= SEQUENCE { + * requestingDeviceIdentifier BACnetObjectIdentifier, + * requestingDeviceAddress BACnetAddress, + * remoteDeviceIdentifier BACnetObjectIdentifier, + * remoteDeviceAddress BACnetAddress + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fRequestKeyRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * Unconfirmed-Service-Request ::= CHOICE { + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @param service_choice + * @return modified offset + */ +static guint +fUnconfirmedServiceRequest (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * I-Am-Request ::= SEQUENCE { + * aAmDeviceIdentifier BACnetObjectIdentifier, + * maxAPDULengthAccepted Unsigned, + * segmentationSupported BACnetSegmentation, + * vendorID Unsigned + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fIAmRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + + +/** + * I-Have-Request ::= SEQUENCE { + * deviceIdentifier BACnetObjectIdentifier, + * objectIdentifier BACnetObjectIdentifier, + * objectName CharacterString + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fIHaveRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * UnconfirmedPrivateTransfer-Request ::= SEQUENCE { + * vendorID [0] Unsigned, + * serviceNumber [1] Unsigned, + * serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fUnconfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fWhoHas (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @param service + * @return modified offset + */ +static guint +fBACnetError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint service); + +/** + * Dissect a BACnetError in a context tag + * + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint fContextTaggedError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * ChangeList-Error ::= SEQUENCE { + * errorType [0] Error, + * firstFailedElementNumber [1] Unsigned + * } + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fChangeListError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * CreateObject-Error ::= SEQUENCE { + * errorType [0] Error, + * firstFailedElementNumber [1] Unsigned + * } + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fCreateObjectError(tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fConfirmedPrivateTransferError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * WritePropertyMultiple-Error ::= SEQUENCE { + * errorType [0] Error, + * firstFailedWriteAttempt [1] Unsigned + * } + * } + * @param tvb + * @pram pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fWritePropertyMultipleError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * VTClose-Error ::= SEQUENCE { + * errorType [0] Error, + * listOfVTSessionIdentifiers [1] SEQUENCE OF Unsigned8 OPTIONAL + * } + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fVTCloseError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * BACnet Application Types chapter 20.2.1 + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @param label + * @return modified offset + */ +static guint +fApplicationTypes (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); + +/** + * 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 pinfo + * @param tree + * @param offset + * @param matching tag number + * @return modified offset + */ +static guint +fActionCommand (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tag_match); + +/** + * BACnetActionList ::= SEQUENCE { + * action [0] SEQUENCE of BACnetActionCommand + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fActionList (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fAddressBinding (tvbuff_t *tvb, packet_info *pinfo, 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, packet_info *pinfo, proto_tree *tree, guint offset); + + +/** + * BACnetDailySchedule ::= SEQUENCE { + * day-schedule [0] SENQUENCE OF BACnetTimeValue + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fDailySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * BACnetWeeklySchedule ::= SEQUENCE { + * week-schedule SENQUENCE SIZE (7) OF BACnetDailySchedule + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fWeeklySchedule (tvbuff_t *tvb, packet_info *pinfo, 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, const gchar *label); + +/** + * BACnetDestination ::= SEQUENCE { + * validDays BACnetDaysOfWeek, + * fromTime Time, + * toTime Time, + * recipient BACnetRecipient, + * processIdentifier Unsigned32, + * issueConfirmedNotifications BOOLEAN, + * transitions BACnetEventTransitionBits + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fDestination (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * BACnetDeviceObjectPropertyReference ::= SEQUENCE { + * objectIdentifier [0] BACnetObjectIdentifier, + * propertyIdentifier [1] BACnetPropertyIdentifier, + * propertyArrayIndex [2] Unsigend OPTIONAL, + * deviceIdentifier [3] BACnetObjectIdentifier OPTIONAL + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fDeviceObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * BACnetDeviceObjectReference ::= SEQUENCE { + * deviceIdentifier [0] BACnetObjectIdentifier OPTIONAL, + * objectIdentifier [1] BACnetObjectIdentifier + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fDeviceObjectReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +#if 0 +/** + * 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); +#endif + + + +/** + * 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fLogRecord (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fNotificationParameters (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fBACnetObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +#if 0 +/** + * 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); +#endif + +/** + * BACnetPriorityArray ::= SEQUENCE SIZE (16) OF BACnetPriorityValue + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fPriorityArray (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +static guint +fPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset, guint8 list); + +/** + * BACnetPropertyReference ::= SEQUENCE { + * propertyIdentifier [0] BACnetPropertyIdentifier, + * propertyArrayIndex [1] Unsigned OPTIONAL, -- used only with array datatype + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fBACnetPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 list); + +/* static guint +fBACnetObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); */ + +static guint +fLOPR (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +static guint +fRestartReason (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fBACnetPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +static guint +fPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset); + +/** + * BACnet Application PDUs chapter 21 + * BACnetRecipient::= CHOICE { + * device [0] BACnetObjectIdentifier + * address [1] BACnetAddress + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fRecipient (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * BACnet Application PDUs chapter 21 + * BACnetRecipientProcess::= SEQUENCE { + * recipient [0] BACnetRecipient + * processID [1] Unsigned32 + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fRecipientProcess (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +#if 0 +/** + * 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); +#endif + +/** + * BACnetSpecialEvent ::= SEQUENCE { + * period CHOICE { + * calendarEntry [0] BACnetCalendarEntry, + * calendarRefernce [1] BACnetObjectIdentifier + * }, + * listOfTimeValues [2] SEQUENCE OF BACnetTimeValue, + * eventPriority [3] Unsigned (1..16) + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fSpecialEvent (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * BACnetTimeStamp ::= CHOICE { + * time [0] Time, + * sequenceNumber [1] Unsigned (0..65535), + * dateTime [2] BACnetDateTime + * } + * @param tvb + * @param tree + * @param offset + * @param label + * @return modified offset + */ +static guint +fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label); + +/** + * BACnetTimeValue ::= SEQUENCE { + * time Time, + * value ABSTRACT-SYNTAX.&Type -- any primitive datatype, complex types cannot be decoded + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fTimeValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +#if 0 +/** + * 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); +#endif + +/** + * 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fReadAccessResult (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * ReadAccessSpecification ::= SEQUENCE { + * objectIdentifier [0] BACnetObjectIdentifier, + * listOfPropertyReferences [1] SEQUENCE OF BACnetPropertyReference + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fReadAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset); + +/** + * WriteAccessSpecification ::= SEQUENCE { + * objectIdentifier [0] BACnetObjectIdentifier, + * listOfProperty [1] SEQUENCE OF BACnetPropertyValue + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fWriteAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, 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, const gchar *label); + +/** + * BACnet Application PDUs chapter 21 + * BACnetPropertyIdentifier::= ENUMERATED { + * @see bacapp_property_identifier + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @param tt returnvalue of this item + * @return modified offset + */ +static guint +fPropertyIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * BACnet Application PDUs chapter 21 + * BACnetPropertyArrayIndex::= ENUMERATED { + * @see bacapp_property_array_index + * } + * @param tvb + * @param tree + * @param offset + * @param tt returnvalue of this item + * @return modified offset + */ +static guint +fPropertyArrayIndex (tvbuff_t *tvb, proto_tree *tree, guint offset); + +/** + * 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +flistOfEventSummaries (tvbuff_t *tvb, packet_info *pinfo, 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 pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * objectSelectionCriteria ::= SEQUENCE { + * selectionLogic [0] ENUMERATED { bacapp_selectionLogic }, + * listOfSelectionCriteria [1] SelectionCriteria + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fObjectSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset); + +/** + * BACnet-Error ::= SEQUENCE { + * error-class ENUMERATED {}, + * error-code ENUMERATED {} + * } + * } + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + */ +static guint +fError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + +/** + * Generic handler for context tagged values. Mostly for handling + * vendor-defined properties and services. + * @param tvb + * @param tree + * @param offset + * @return modified offset + * @todo beautify this ugly construct + */ +static guint +fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label); + +/** + * realizes some ABSTRACT-SYNTAX.&Type + * @param tvb + * @param pinfo + * @param tree + * @param offset + * @return modified offset + * @todo beautify this ugly construct + */ +static guint +fAbstractSyntaxNType (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); + + +static guint +fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, + const value_string *src); + +/** + * register_bacapp + */ +void +proto_register_bacapp(void); + +/** + * proto_reg_handoff_bacapp + */ +void +proto_reg_handoff_bacapp(void); + +/** + * converts XXX coded strings to UTF-8 + * else 'in' is copied to 'out' + * @param in -- pointer to string + * @param inbytesleft + * @param out -- pointer to string + * @param outbytesleft + * @param fromcoding + * @return count of modified characters of returned string, -1 for errors + */ +static guint32 +fConvertXXXtoUTF8(gchar *in, gsize *inbytesleft, gchar *out, gsize *outbytesleft, const gchar *fromcoding); + +static void +uni_to_string(char * data, gsize str_length, char *dest_buf); + +/* <<<< formerly bacapp.h */ + +/* some hashes for segmented messages */ +static GHashTable *msg_fragment_table = NULL; +static GHashTable *msg_reassembled_table = NULL; /* some necessary forward function prototypes */ static guint -fApplicationTypesEnumerated (tvbuff_t *tvb, proto_tree *tree, guint offset, +fApplicationTypesEnumerated (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *vs); static const char *bacapp_unknown_service_str = "unknown service"; @@ -40,14 +2175,14 @@ static const char *Vendor_Proprietary_Fmt = "(%d) Vendor Proprietary Value"; static const value_string BACnetTypeName[] = { - {0, "Confirmed-Request "}, - {1, "Unconfirmed-Request "}, - {2, "SimpleACK "}, - {3, "ComplexACK "}, - {4, "SegmentACK "}, - {5, "Error "}, - {6, "Reject "}, - {7, "Abort "}, + {0, "Confirmed-REQ"}, + {1, "Unconfirmed-REQ"}, + {2, "Simple-ACK"}, + {3, "Complex-ACK"}, + {4, "Segment-ACK"}, + {5, "Error"}, + {6, "Reject"}, + {7, "Abort"}, {0, NULL } }; @@ -121,6 +2256,19 @@ BACnetRejectReason [] = { {0,NULL} }; +static const value_string +BACnetRestartReason [] = { + {0,"unknown"}, + {1,"coldstart"}, + {2,"warmstart"}, + {3,"detected-power-lost"}, + {4,"detected-powered-off"}, + {5,"hardware-watchdog"}, + {6,"software-watchdog"}, + {7,"suspended"}, + {0,NULL} +}; + static const value_string BACnetApplicationTagNumber [] = { {0,"Null"}, @@ -156,6 +2304,38 @@ BACnetFileAccessMethod [] = { {0,NULL} }; +/* For some reason, BACnet defines the choice parameter + in the file read and write services backwards from the + BACnetFileAccessMethod enumeration. +*/ +static const value_string +BACnetFileAccessOption [] = { + {0,"stream access"}, + {1,"record access"}, + {0,NULL} +}; + +static const value_string +BACnetFileStartOption [] = { + {0, "File Start Position: "}, + {1, "File Start Record: "}, + {0, NULL} +}; + +static const value_string +BACnetFileRequestCount [] = { + {0, "Requested Octet Count: "}, + {1, "Requested Record Count: "}, + {0, NULL} +}; + +static const value_string +BACnetFileWriteInfo [] = { + {0, "File Data: "}, + {1, "Record Count: "}, + {0, NULL} +}; + static const value_string BACnetAbortReason [] = { {0,"other"}, @@ -202,8 +2382,8 @@ BACnetLifeSafetyOperation [] = { {8,"unsilence-audible"}, {9,"unsilence-visual"}, {0,NULL} -/* Enumerated values 0-63 are reserved for definition by ASHRAE. - Enumerated values 64-65535 may be used by others subject to +/* Enumerated values 0-63 are reserved for definition by ASHRAE. + Enumerated values 64-65535 may be used by others subject to procedures and constraints described in Clause 23. */ }; @@ -241,8 +2421,8 @@ BACnetLifeSafetyState [] = { {22,"supervisory"}, {23,"test-supervisory"}, {0,NULL} -/* Enumerated values 0-255 are reserved for definition by ASHRAE. - Enumerated values 256-65535 may be used by others subject to +/* Enumerated values 0-255 are reserved for definition by ASHRAE. + Enumerated values 256-65535 may be used by others subject to procedures and constraints described in Clause 23. */ }; @@ -329,31 +2509,55 @@ BACnetUnconfirmedServiceRequest [] = { 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"}, - {23,"accumulator object"}, - {24,"pulse-converter object"}, + {0,"analog-input"}, + {1,"analog-output"}, + {2,"analog-value"}, + {3,"binary-input"}, + {4,"binary-output"}, + {5,"binary-value"}, + {6,"calendar"}, + {7,"command"}, + {8,"device"}, + {9,"event-enrollment"}, + {10,"file"}, + {11,"group"}, + {12,"loop"}, + {13,"multi-state-input"}, + {14,"multi-state-output"}, + {15,"notification-class"}, + {16,"program"}, + {17,"schedule"}, + {18,"averaging"}, + {19,"multi-state-value"}, + {20,"trend-log"}, + {21,"life-safety-point"}, + {22,"life-safety-zone"}, + {23,"accumulator"}, + {24,"pulse-converter"}, + {25,"event-log"}, + {26,"global-group"}, + {27,"trend-log-multiple"}, + {28,"load-control"}, + {29,"structured-view"}, + {30,"access-door"}, /* 30-37 added with addanda 135-2008j */ + {32,"access-credential"}, + {33,"access-point"}, + {34,"access-rights"}, + {35,"access-user"}, + {36,"access-zone"}, + {37,"credential-data-input"}, + {39,"bitstring-value"}, /* 39-50 added with addenda 135-2008w */ + {40,"characterstring-value"}, + {41,"date-pattern-value"}, + {42,"date-value"}, + {43,"datetime-pattern-value"}, + {44,"datetime-value"}, + {45,"integer-value"}, + {46,"large-analog-value"}, + {47,"octetstring-value"}, + {48,"positive-Integer-value"}, + {49,"time-pattern-value"}, + {50,"time-value"}, {0, NULL} /* Enumerated values 0-127 are reserved for definition by ASHRAE. Enumerated values 128-1023 may be used by others subject to @@ -375,7 +2579,7 @@ BACnetEngineeringUnits [] = { {10,"Megavolt Amperes"}, {11,"Volt Amperes Reactive"}, {12,"Kilovolt Amperes Reactive"}, - {13,"Megavolt Amperes Ractive"}, + {13,"Megavolt Amperes Reactive"}, {14,"Degrees Phase"}, {15,"Power Factor"}, {16,"Joules"}, @@ -390,7 +2594,7 @@ BACnetEngineeringUnits [] = { {25,"Cycles Per Hour"}, {26,"Cycles Per Minute"}, {27,"Hertz"}, - {28,"Gramms Of Water Per Kilogram Dry Air"}, + {28,"Grams Of Water Per Kilogram Dry Air"}, {29,"Relative Humidity"}, {30,"Millimeters"}, {31,"Meters"}, @@ -400,7 +2604,7 @@ BACnetEngineeringUnits [] = { {35,"Watts Per Sq meter"}, {36,"Lumens"}, {37,"Lux"}, - {38,"Foot Candels"}, + {38,"Foot Candles"}, {39,"Kilograms"}, {40,"Pounds Mass"}, {41,"Tons"}, @@ -425,7 +2629,7 @@ BACnetEngineeringUnits [] = { {60,"Centimeters Of Mercury"}, {61,"Inches Of Mercury"}, {62,"Degrees Celsius"}, - {63,"Degress Kelvin"}, + {63,"Degrees Kelvin"}, {64,"Degrees Fahrenheit"}, {65,"Degree Days Celsius"}, {66,"Degree Days Fahrenheit"}, @@ -553,8 +2757,8 @@ BACnetEngineeringUnits [] = { {188,"newtons-per-meter"}, {189,"watts-per-meter-per-degree-Kelvin"}, {0,NULL} -/* Enumerated values 0-255 are reserved for definition by ASHRAE. - Enumerated values 256-65535 may be used by others subject to +/* Enumerated values 0-255 are reserved for definition by ASHRAE. + Enumerated values 256-65535 may be used by others subject to the procedures and constraints described in Clause 23. */ }; @@ -562,9 +2766,9 @@ static const value_string BACnetErrorCode [] = { {0,"other"}, {1,"authentication-failed"}, - {2,"character-set-not-supported"}, - {3,"configuration-in-progress"}, - {4,"device-busy"}, + {2,"configuration-in-progress"}, + {3,"device-busy"}, + {4,"dynamic-creation-not-supported"}, {5,"file-access-denied"}, {6,"incompatible-security-levels"}, {7,"inconsistent-parameters"}, @@ -605,15 +2809,17 @@ BACnetErrorCode [] = { {42,"invalid-array-index"}, {43,"cov-subscription-failed"}, {44,"not-cov-property"}, - {45,"optional-functionaltity-not-supported"}, + {45,"optional-functionality-not-supported"}, {46,"invalid-configuration-data"}, {47,"datatype-not-supported"}, {48,"duplicate-name"}, {49,"duplicate-object-id"}, {50,"property-is-not-an-array"}, + {73,"invalid-event-state"}, + {74,"no-alarm-configured"}, {0, NULL} -/* Enumerated values 0-255 are reserved for definition by ASHRAE. - Enumerated values 256-65535 may be used by others subject to the +/* Enumerated values 0-255 are reserved for definition by ASHRAE. + Enumerated values 256-65535 may be used by others subject to the procedures and constraints described in Clause 23. */ }; @@ -752,7 +2958,7 @@ BACnetPropertyIdentifier [] = { {130,"event-time-stamp"}, {131,"log-buffer"}, {132,"log-device-object-property"}, - {133,"log-enable"}, + {133,"enable"}, /* per ANSI/ASHRAE 135-2004 addendum B */ {134,"log-interval"}, {135,"maximum-value"}, {136,"minimum-value"}, @@ -792,7 +2998,7 @@ BACnetPropertyIdentifier [] = { {170,"manual-slave-address-binding"}, {171,"slave-address-binding"}, {172,"slave-proxy-enable"}, - {173,"last-notify-time"}, + {173,"last-notify-record"}, /* bug 4117 */ {174,"schedule-default"}, {175,"accepted-modes"}, {176,"adjust-value"}, @@ -812,9 +3018,130 @@ BACnetPropertyIdentifier [] = { {190,"value-before-change"}, {191,"value-set"}, {192,"value-change-time"}, + {193,"align-intervals"}, + {194,"group-member-names"}, + {195,"interval-offset"}, + {196,"last-restart-reason"}, + {197,"logging-type"}, + {198,"member-status-flags"}, + {199,"notification-period"}, + {200,"previous-notify-record"}, + {201,"requested-update-interval"}, + {202,"restart-notification-recipients"}, + {203,"time-of-device-restart"}, + {204,"time-synchronization-recipients"}, + {205,"trigger"}, + {206,"UTC-time-synchronization-recipients"}, + {207,"node-subtype"}, + {208,"node-type"}, + {209,"structured-object-list"}, + {210,"subordinate-annotations"}, + {211,"subordinate-list"}, + {212,"actual-shed-level"}, + {213,"duty-window"}, + {214,"expected-shed-level"}, + {215,"full-duty-baseline"}, + {216,"node-subtype"}, + {217,"node-type"}, + {218,"requested-shed-level"}, + {219,"shed-duration"}, + {220,"shed-level-descriptions"}, + {221,"shed-levels"}, + {222,"state-description"}, + {226,"door-alarm-state"}, + {227,"door-extended-pulse-time"}, + {228,"door-members"}, + {229,"door-open-too-long-time"}, + {230,"door-pulse-time"}, + {231,"door-status"}, + {232,"door-unlock-delay-time"}, + {233,"lock-status"}, + {234,"masked-alarm-values"}, + {235,"secured-status"}, + {244,"absentee-limit"}, /* added with addenda 135-2008j */ + {245,"access-alarm-events"}, + {246,"access-doors"}, + {247,"access-event"}, + {248,"access-event-authentication-factor"}, + {249,"access-event-credential"}, + {250,"access-event-time"}, + {251,"access-transaction-events"}, + {252,"accompaniment"}, + {253,"accompaniment-time"}, + {254,"activation-time"}, + {255,"active-authentication-policy"}, + {256,"assigned-access-rights"}, + {257,"authentication-factors"}, + {258,"authentication-policy-list"}, + {259,"authentication-policy-names"}, + {260,"authentication-status"}, + {261,"authorization-mode"}, + {262,"belongs-to"}, + {263,"credential-disable"}, + {264,"credential-status"}, + {265,"credentials"}, + {266,"credentials-in-zone"}, + {267,"days-remaining"}, + {268,"entry-points"}, + {269,"exit-points"}, + {270,"expiry-time"}, + {271,"extended-time-enable"}, + {272,"failed-attempt-events"}, + {273,"failed-attempts"}, + {274,"failed-attempts-time"}, + {275,"last-access-event"}, + {276,"last-access-point"}, + {277,"last-credential-added"}, + {278,"last-credential-added-time"}, + {279,"last-credential-removed"}, + {280,"last-credential-removed-time"}, + {281,"last-use-time"}, + {282,"lockout"}, + {283,"lockout-relinquish-time"}, + {284,"master-exemption"}, + {285,"max-failed-attempts"}, + {286,"members"}, + {287,"muster-point"}, + {288,"negative-access-rules"}, + {289,"number-of-authentication-policies"}, + {290,"occupancy-count"}, + {291,"occupancy-count-adjust"}, + {292,"occupancy-count-enable"}, + {293,"occupancy-exemption"}, + {294,"occupancy-lower-limit"}, + {295,"occupancy-lower-limit-enforced"}, + {296,"occupancy-state"}, + {297,"occupancy-upper-limit"}, + {298,"occupancy-upper-limit-enforced"}, + {299,"passback-exemption"}, + {300,"passback-mode"}, + {301,"passback-timeout"}, + {302,"positive-access-rules"}, + {303,"reason-for-disable"}, + {304,"supported-formats"}, + {305,"supported-format-classes"}, + {306,"threat-authority"}, + {307,"threat-level"}, + {308,"trace-flag"}, + {309,"transaction-notification-class"}, + {310,"user-external-identifier"}, + {311,"user-information-reference"}, + /* enumeration values 312-316 reserved for future addenda */ + {317,"user-name"}, + {318,"user-type"}, + {319,"uses-remaining"}, + {320,"zone-from"}, + {321,"zone-to"}, + {322,"access-event-tag"}, + {323,"global-identifier"}, + /* enumeration values 324-325 reserved for future addenda */ + {326,"verification-time"}, + {342,"bit-mask"}, /* addenda 135-2008w */ + {343,"bit-text"}, + {344,"is-utc"}, {0, NULL} -/* Enumerated values 0-511 are reserved for definition by ASHRAE. - Enumerated values 512-4194303 may be used by others subject to +/* Enumerated values 0-511 are reserved for definition by ASHRAE. + Enumerated values 512-4194303 may be used by others subject to the procedures and constraints described in Clause 23. */ }; @@ -826,15 +3153,21 @@ BACnetBinaryPV [] = { }; +#define ANSI_X34 0 +#define IBM_MS_DBCS 1 +#define JIS_C_6226 2 +#define ISO_10646_UCS4 3 +#define ISO_10646_UCS2 4 +#define ISO_18859_1 5 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} + {ANSI_X34, "ANSI X3.4 / UTF-8 (since 2010)"}, + {IBM_MS_DBCS, "IBM/Microsoft DBCS"}, + {JIS_C_6226, "JIS C 6226"}, + {ISO_10646_UCS4, "ISO 10646(UCS-4)"}, + {ISO_10646_UCS2, "ISO 10646(UCS-2)"}, + {ISO_18859_1, "ISO 18859-1"}, + {0, NULL} }; static const value_string @@ -973,8 +3306,10 @@ weekofmonth [] = { {0,NULL } }; +/* note: notification class object recipient-list uses + different day-of-week enum */ static const value_string -days [] = { +day_of_week [] = { {1,"Monday" }, {2,"Tuesday" }, {3,"Wednesday" }, @@ -983,7 +3318,7 @@ days [] = { {6,"Saturday" }, {7,"Sunday" }, {255,"any day of week" }, - {0,NULL }, + {0,NULL } }; static const value_string @@ -995,9 +3330,9 @@ BACnetErrorClass [] = { {4,"security" }, {5,"services" }, {6,"vt" }, - {0,NULL }, -/* Enumerated values 0-63 are reserved for definition by ASHRAE. - Enumerated values64-65535 may be used by others subject to + {0,NULL } +/* Enumerated values 0-63 are reserved for definition by ASHRAE. + Enumerated values64-65535 may be used by others subject to the procedures and constraints described in Clause 23. */ }; @@ -1010,7 +3345,7 @@ BACnetVTClass [] = { {4,"dec-vt200" }, {5,"hp-700-94" }, {6,"ibm-3130" }, - {0,NULL }, + {0,NULL } }; static const value_string @@ -1027,12 +3362,16 @@ BACnetEventType [] = { {9,"extended" }, {10,"buffer-ready" }, {11,"unsigned-range" }, - {0,NULL }, -/* Enumerated values 0-63 are reserved for definition by ASHRAE. - Enumerated values 64-65535 may be used by others subject to - the procedures and constraints described in Clause 23. - It is expected that these enumerated values will correspond - to the use of the complex-event-type CHOICE [6] of the + {14,"double-out-of-range"}, /* added with addenda 135-2008w */ + {15,"signed-out-of-range"}, + {16,"unsigned-out-of-range"}, + {17,"change-of-characterstring"}, + {0,NULL } +/* Enumerated values 0-63 are reserved for definition by ASHRAE. + Enumerated values 64-65535 may be used by others subject to + the procedures and constraints described in Clause 23. + It is expected that these enumerated values will correspond + to the use of the complex-event-type CHOICE [6] of the BACnetNotificationParameters production. */ }; @@ -1044,9 +3383,9 @@ BACnetEventState [] = { {3,"high-limit" }, {4,"low-limit" }, {5,"life-safety-alarm" }, - {0,NULL }, -/* Enumerated values 0-63 are reserved for definition by ASHRAE. - Enumerated values 64-65535 may be used by others subject to + {0,NULL } +/* Enumerated values 0-63 are reserved for definition by ASHRAE. + Enumerated values 64-65535 may be used by others subject to the procedures and constraints described in Clause 23. */ }; @@ -1054,7 +3393,7 @@ static const value_string BACnetLogStatus [] = { {0,"log-disabled" }, {1,"buffer-purged" }, - {0,NULL }, + {0,NULL } }; static const value_string @@ -1063,7 +3402,7 @@ BACnetMaintenance [] = { {1,"periodic-test" }, {2,"need-service-operational" }, {3,"need-service-inoperative" }, - {0,NULL }, + {0,NULL } }; static const value_string @@ -1071,7 +3410,7 @@ BACnetNotifyType [] = { {0,"alarm" }, {1,"event" }, {2,"ack-notification" }, - {0,NULL }, + {0,NULL } }; static const value_string @@ -1135,10 +3474,11 @@ BACnetPropertyStates [] = { {11,"unsigned-value"}, {12,"life-safety-mode"}, {13,"life-safety-state"}, + {14,"door-alarm-state"}, {0,NULL} -/* Tag values 0-63 are reserved for definition by ASHRAE. - Tag values of 64-254 may be used by others to accommodate - vendor specific properties that have discrete or enumerated values, +/* Tag values 0-63 are reserved for definition by ASHRAE. + Tag values of 64-254 may be used by others to accommodate + vendor specific properties that have discrete or enumerated values, subject to the constraints described in Clause 23. */ }; @@ -1150,8 +3490,8 @@ BACnetProgramError [] = { {3,"program"}, {4,"other"}, {0,NULL} -/* Enumerated values 0-63 are reserved for definition by ASHRAE. - Enumerated values 64-65535 may be used by others subject to +/* Enumerated values 0-63 are reserved for definition by ASHRAE. + Enumerated values 64-65535 may be used by others subject to the procedures and constraints described in Clause 23. */ }; @@ -1204,6 +3544,375 @@ BACnetTagNames[] = { { 0, NULL } }; +static const value_string +BACnetReadRangeOptions[] = { + { 3, "range byPosition" }, + { 4, "range byTime" }, + { 5, "range timeRange" }, + { 6, "range bySequenceNumber" }, + { 7, "range byTime" }, + { 0, NULL } +}; + +/* Present_Value for Load Control Object */ +static const value_string +BACnetShedState[] = { + { 0, "shed-inactive" }, + { 1, "shed-request-pending" }, + { 2, "shed-compliant" }, + { 3, "shed-non-compliant" }, + { 0, NULL } +}; + +static const value_string +BACnetVendorIdentifiers [] = { + { 0, "ASHRAE" }, + { 1, "NIST" }, + { 2, "The Trane Company" }, + { 3, "McQuay International" }, + { 4, "PolarSoft" }, + { 5, "Johnson Controls, Inc." }, + { 6, "American Auto-Matrix" }, + { 7, "Siemens Building Technologies, Ltd., Landis & Staefa Division Europe" }, + { 8, "Delta Controls" }, + { 9, "Siemens Building Technologies, Inc." }, + { 10, "Tour Andover Controls Corporation" }, + { 11, "TAC" }, + { 12, "Orion Analysis Corporation" }, + { 13, "Teletrol Systems Inc." }, + { 14, "Cimetrics Technology" }, + { 15, "Cornell University" }, + { 16, "United Technologies Carrier" }, + { 17, "Honeywell Inc." }, + { 18, "Alerton / Honeywell" }, + { 19, "TAC AB" }, + { 20, "Hewlett-Packard Company" }, + { 21, "Dorsette's Inc." }, + { 22, "Cerberus AG" }, + { 23, "York Controls Group" }, + { 24, "Automated Logic Corporation" }, + { 25, "CSI Control Systems International" }, + { 26, "Phoenix Controls Corporation" }, + { 27, "Innovex Technologies, Inc." }, + { 28, "KMC Controls, Inc." }, + { 29, "Xn Technologies, Inc." }, + { 30, "Hyundai Information Technology Co., Ltd." }, + { 31, "Tokimec Inc." }, + { 32, "Simplex" }, + { 33, "North Communications Limited" }, + { 34, "Notifier" }, + { 35, "Reliable Controls Corporation" }, + { 36, "Tridium Inc." }, + { 37, "Sierra Monitor Corp." }, + { 38, "Silicon Energy" }, + { 39, "Kieback & Peter GmbH & Co KG" }, + { 40, "Anacon Systems, Inc." }, + { 41, "Systems Controls & Instruments, LLC" }, + { 42, "Lithonia Lighting" }, + { 43, "Micropower Manufacturing" }, + { 44, "Matrix Controls" }, + { 45, "METALAIRE" }, + { 46, "ESS Engineering" }, + { 47, "Sphere Systems Pty Ltd." }, + { 48, "Walker Technologies Corporation" }, + { 49, "H I Solutions, Inc." }, + { 50, "MBS GmbH" }, + { 51, "SAMSON AG" }, + { 52, "Badger Meter Inc." }, + { 53, "DAIKIN Industries Ltd." }, + { 54, "NARA Controls Inc." }, + { 55, "Mammoth Inc." }, + { 56, "Liebert Corporation" }, + { 57, "SEMCO Incorporated" }, + { 58, "Air Monitor Corporation" }, + { 59, "TRIATEK, Inc." }, + { 60, "NexLight" }, + { 61, "Multistack" }, + { 62, "TSI Incorporated" }, + { 63, "Weather-Rite, Inc." }, + { 64, "Dunham-Bush" }, + { 65, "Reliance Electric" }, + { 66, "LCS Inc." }, + { 67, "Regulator Australia PTY Ltd." }, + { 68, "Touch-Plate Lighting Controls" }, + { 69, "Amann GmbH" }, + { 70, "RLE Technologies" }, + { 71, "Cardkey Systems" }, + { 72, "SECOM Co., Ltd." }, + { 73, "ABB Gebaudetechnik AG Bereich NetServ" }, + { 74, "KNX Association cvba" }, + { 75, "Institute of Electrical Installation Engineers of Japan (IEIEJ)" }, + { 76, "Nohmi Bosai, Ltd." }, + { 77, "Carel S.p.A." }, + { 78, "AirSense Technology, Inc." }, + { 79, "Hochiki Corporation" }, + { 80, "Fr. Sauter AG" }, + { 81, "Matsushita Electric Works, Ltd." }, + { 82, "Mitsubishi Electric Corporation, Inazawa Works" }, + { 83, "Mitsubishi Heavy Industries, Ltd." }, + { 84, "ITT Bell & Gossett" }, + { 85, "Yamatake Building Systems Co., Ltd." }, + { 86, "The Watt Stopper, Inc." }, + { 87, "Aichi Tokei Denki Co., Ltd." }, + { 88, "Activation Technologies, LLC" }, + { 89, "Saia-Burgess Controls, Ltd." }, + { 90, "Hitachi, Ltd." }, + { 91, "Novar Corp./Trend Control Systems Ltd." }, + { 92, "Mitsubishi Electric Lighting Corporation" }, + { 93, "Argus Control Systems, Ltd." }, + { 94, "Kyuki Corporation" }, + { 95, "Richards-Zeta Building Intelligence, Inc." }, + { 96, "Scientech R&D, Inc." }, + { 97, "VCI Controls, Inc." }, + { 98, "Toshiba Corporation" }, + { 99, "Mitsubishi Electric Corporation Air Conditioning & Refrigeration Systems Works" }, + { 100, "Custom Mechanical Equipment, LLC" }, + { 101, "ClimateMaster" }, + { 102, "ICP Panel-Tec, Inc." }, + { 103, "D-Tek Controls" }, + { 104, "NEC Engineering, Ltd." }, + { 105, "PRIVA BV" }, + { 106, "Meidensha Corporation" }, + { 107, "JCI Systems Integration Services" }, + { 108, "Freedom Corporation" }, + { 109, "Neuberger Gebaudeautomation GmbH" }, + { 110, "Sitronix" }, + { 111, "Leviton Manufacturing" }, + { 112, "Fujitsu Limited" }, + { 113, "Emerson Network Power" }, + { 114, "S. A. Armstrong, Ltd." }, + { 115, "Visonet AG" }, + { 116, "M&M Systems, Inc." }, + { 117, "Custom Software Engineering" }, + { 118, "Nittan Company, Limited" }, + { 119, "Elutions Inc. (Wizcon Systems SAS)" }, + { 120, "Pacom Systems Pty., Ltd." }, + { 121, "Unico, Inc." }, + { 122, "Ebtron, Inc." }, + { 123, "Scada Engine" }, + { 124, "AC Technology Corporation" }, + { 125, "Eagle Technology" }, + { 126, "Data Aire, Inc." }, + { 127, "ABB, Inc." }, + { 128, "Transbit Sp. z o. o." }, + { 129, "Toshiba Carrier Corporation" }, + { 130, "Shenzhen Junzhi Hi-Tech Co., Ltd." }, + { 131, "Tokai Soft" }, + { 132, "Lumisys" }, + { 133, "Veris Industries" }, + { 134, "Centaurus Prime" }, + { 135, "Sand Network Systems" }, + { 136, "Regulvar, Inc." }, + { 137, "Fastek International, Ltd." }, + { 138, "PowerCold Comfort Air Solutions, Inc." }, + { 139, "I Controls" }, + { 140, "Viconics Electronics, Inc." }, + { 141, "Yaskawa Electric America, Inc." }, + { 142, "Plueth Regelsysteme" }, + { 143, "Digitale Mess- und Steuersysteme AG" }, + { 144, "Fujitsu General Limited" }, + { 145, "Project Engineering S.r.l." }, + { 146, "Sanyo Electric Co., Ltd." }, + { 147, "Integrated Information Systems, Inc." }, + { 148, "Temco Controls, Ltd." }, + { 149, "Airtek Technologies, Inc." }, + { 150, "Advantech Corporation" }, + { 151, "Titan Products, Ltd." }, + { 152, "Regel Partners" }, + { 153, "National Environmental Product" }, + { 154, "Unitec Corporation" }, + { 155, "Kanden Engineering Company" }, + { 156, "Messner Gebaudetechnik GmbH" }, + { 157, "Integrated.CH" }, + { 158, "EH Price Limited" }, + { 159, "SE-Elektronic GmbH" }, + { 160, "Rockwell Automation" }, + { 161, "Enflex Corp." }, + { 162, "ASI Controls" }, + { 163, "SysMik GmbH Dresden" }, + { 164, "HSC Regelungstechnik GmbH" }, + { 165, "Smart Temp Australia Pty. Ltd." }, + { 166, "PCI Lighting Control Systems" }, + { 167, "Duksan Mecasys Co., Ltd." }, + { 168, "Fuji IT Co., Ltd." }, + { 169, "Vacon Plc" }, + { 170, "Leader Controls" }, + { 171, "Cylon Controls, Ltd." }, + { 172, "Compas" }, + { 173, "Mitsubishi Electric Building Techno-Service Co., Ltd." }, + { 174, "Building Control Integrators" }, + { 175, "ITG Worldwide (M) Sdn Bhd" }, + { 176, "Lutron Electronics Co., Inc." }, + { 177, "Cooper-Atkins Corporation" }, + { 178, "LOYTEC Electronics GmbH" }, + { 179, "ProLon" }, + { 180, "Mega Controls Limited" }, + { 181, "Micro Control Systems, Inc." }, + { 182, "Kiyon, Inc." }, + { 183, "Dust Networks" }, + { 184, "Advanced Building Automation Systems" }, + { 185, "Hermos AG" }, + { 186, "CEZIM" }, + { 187, "Softing" }, + { 188, "Lynxspring" }, + { 189, "Schneider Toshiba Inverter Europe" }, + { 190, "Danfoss Drives A/S" }, + { 191, "Eaton Corporation" }, + { 192, "Matyca S.A." }, + { 193, "Botech AB" }, + { 194, "Noveo, Inc." }, + { 195, "AMEV" }, + { 196, "Yokogawa Electric Corporation" }, + { 197, "GFR Gesellschaft fur Regelungstechnik" }, + { 198, "Exact Logic" }, + { 199, "Mass Electronics Pty Ltd dba Innotech Control Systems Australia" }, + { 200, "Kandenko Co., Ltd." }, + { 201, "DTF, Daten-Technik Fries" }, + { 202, "Klimasoft, Ltd." }, + { 203, "Toshiba Schneider Inverter Corporation" }, + { 204, "Control Applications, Ltd." }, + { 205, "KDT Systems Co., Ltd." }, + { 206, "Onicon Incorporated" }, + { 207, "Automation Displays, Inc." }, + { 208, "Control Solutions, Inc." }, + { 209, "Remsdaq Limited" }, + { 210, "NTT Facilities, Inc." }, + { 211, "VIPA GmbH" }, + { 212, "TSC21 Association of Japan" }, + { 213, "BBP Energie Ltee" }, + { 214, "HRW Limited" }, + { 215, "Lighting Control & Design, Inc." }, + { 216, "Mercy Electronic and Electrical Industries" }, + { 217, "Samsung SDS Co., Ltd" }, + { 218, "Impact Facility Solutions, Inc." }, + { 219, "Aircuity" }, + { 220, "Control Techniques, Ltd." }, + { 221, "Evolve Control Systems, LLC" }, + { 222, "WAGO Kontakttechnik GmbH & Co. KG" }, + { 223, "Cerus Industrial" }, + { 224, "Chloride Power Protection Company" }, + { 225, "Computrols, Inc." }, + { 226, "Phoenix Contact GmbH & Co. KG" }, + { 227, "Grundfos Management A/S" }, + { 228, "Ridder Drive Systems" }, + { 229, "Soft Device SDN BHD" }, + { 230, "Integrated Control Technology Limited" }, + { 231, "AIRxpert Systems, Inc." }, + { 232, "Microtrol Limited" }, + { 233, "Red Lion Controls" }, + { 234, "Digital Electronics Corporation" }, + { 235, "Ennovatis GmbH" }, + { 236, "Serotonin Software Technologies, Inc." }, + { 237, "LS Industrial Systems Co., Ltd." }, + { 238, "Square D Company" }, + { 239, "S Squared Innovations, Inc." }, + { 240, "Aricent Ltd." }, + { 241, "EtherMetrics, LLC" }, + { 242, "Industrial Control Communications, Inc." }, + { 243, "Paragon Controls, Inc." }, + { 244, "A. O. Smith Corporation" }, + { 245, "Contemporary Control Systems, Inc." }, + { 246, "Intesis Software SL" }, + { 247, "Ingenieurgesellschaft N. Hartleb mbH" }, + { 248, "Heat-Timer Corporation" }, + { 249, "Ingrasys Technology, Inc." }, + { 250, "Costerm Building Automation" }, + { 251, "Wilo AG" }, + { 252, "Embedia Technologies Corp." }, + { 253, "Technilog" }, + { 254, "HR Controls Ltd. & Co. KG" }, + { 255, "Lennox International, Inc." }, + { 256, "RK-Tec Rauchklappen-Steuerungssysteme GmbH & Co. KG" }, + { 257, "Thermomax, Ltd." }, + { 258, "ELCON Electronic Control, Ltd." }, + { 259, "Larmia Control AB" }, + { 260, "BACnet Stack at SourceForge" }, + { 261, "G4S Security Services A/S" }, + { 262, "Sitek S.p.A." }, + { 263, "Cristal Controles" }, + { 264, "Regin AB" }, + { 265, "Dimension Software, Inc. " }, + { 266, "SynapSense Corporation" }, + { 267, "Beijing Nantree Electronic Co., Ltd." }, + { 268, "Camus Hydronics Ltd." }, + { 269, "Kawasaki Heavy Industries, Ltd. " }, + { 270, "Critical Environment Technologies" }, + { 271, "ILSHIN IBS Co., Ltd." }, + { 272, "ELESTA Energy Control AG" }, + { 273, "KROPMAN Installatietechniek" }, + { 274, "Baldor Electric Company" }, + { 275, "INGA mbH" }, + { 276, "GE Consumer & Industrial" }, + { 277, "Functional Devices, Inc." }, + { 278, "ESAC" }, + { 279, "M-System Co., Ltd." }, + { 280, "Yokota Co., Ltd." }, + { 281, "Hitranse Technology Co., LTD" }, + { 282, "Federspiel Controls" }, + { 283, "Kele, Inc." }, + { 284, "Opera Electronics, Inc." }, + { 285, "Gentec" }, + { 286, "Embedded Science Labs, LLC" }, + { 287, "Parker Hannifin Corporation" }, + { 288, "MaCaPS International Limited" }, + { 289, "Link4 Corporation" }, + { 290, "Romutec Steuer-u. Regelsysteme GmbH" }, + { 291, "Pribusin, Inc." }, + { 292, "Advantage Controls" }, + { 293, "Critical Room Control" }, + { 294, "LEGRAND" }, + { 295, "Tongdy Control Technology Co., Ltd." }, + { 296, "ISSARO Integrierte Systemtechnik" }, + { 297, "Pro-Dev Industries" }, + { 298, "DRI-STEEM" }, + { 299, "Creative Electronic GmbH" }, + { 300, "Swegon AB" }, + { 301, "Jan Brachacek" }, + { 302, "Hitachi Appliances, Inc." }, + { 303, "Real Time Automation, Inc." }, + { 304, "ITEC Hankyu-Hanshin Co." }, + { 305, "Cyrus E&M Engineering Co., Ltd." }, + { 306, "Racine Federated, Inc." }, + { 307, "Verari Systems, Inc." }, + { 308, "Elesta GmbH Building Automation" }, + { 309, "Securiton" }, + { 310, "OSlsoft, Inc." }, + { 311, "Hanazeder Electronic GmbH" }, + { 312, "Honeywell Security Deutschland, Novar GmbH" }, + { 313, "Siemens Energy & Automation, Inc." }, + { 314, "ETM Professional Control GmbH" }, + { 315, "Meitav-tec, Ltd." }, + { 316, "Janitza Electronics GmbH" }, + { 317, "MKS Nordhausen" }, + { 318, "De Gier Drive Systems B.V." }, + { 319, "Cypress Envirosystems" }, + { 320, "SMARTron s.r.o." }, + { 321, "Verari Systems, Inc." }, + { 322, "K-W Electronic Service, Inc." }, + { 323, "ALFA-SMART Energy Management" }, + { 324, "Telkonet, Inc." }, + { 325, "Securiton GmbH" }, + { 326, "Cemtrex, Inc." }, + { 327, "Performance Technologies, Inc." }, + { 328, "Xtralis (Aust) Pty Ltd" }, + { 329, "TROX GmbH" }, + { 330, "Beijing Hysine Technology Co., Ltd" }, + { 331, "RCK Controls, Inc." }, + { 332, "ACELIA" }, + { 333, "Novar/Honeywell" }, + { 334, "The S4 Group, Inc." }, + { 335, "Schneider Electric" }, + { 336, "LHA Systems" }, + { 337, "GHM engineering Group, Inc." }, + { 338, "Cllimalux S.A." }, + { 339, "VAISALA Oyj" }, + { 340, "COMPLEX (Beijing) Technology, Co., LTD." }, + { 342, "POWERPEG NSI Limited" }, + { 343, "BACnet Interoperability Testing Services, Inc." }, + { 344, "Teco a.s." }, + { 0, NULL } +}; + static int proto_bacapp = -1; static int hf_bacapp_type = -1; static int hf_bacapp_pduflags = -1; @@ -1236,9 +3945,26 @@ static int hf_bacapp_tag_value32 = -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 int hf_BACnetPropertyIdentifier = -1; +static int hf_BACnetVendorIdentifier = -1; +static int hf_BACnetRestartReason = -1; +static int hf_bacapp_tag_IPV4 = -1; +static int hf_bacapp_tag_IPV6 = -1; +static int hf_bacapp_tag_PORT = -1; +/* some more variables for segmented messages */ +static int hf_msg_fragments = -1; +static int hf_msg_fragment = -1; +static int hf_msg_fragment_overlap = -1; +static int hf_msg_fragment_overlap_conflicts = -1; +static int hf_msg_fragment_multiple_tails = -1; +static int hf_msg_fragment_too_long_fragment = -1; +static int hf_msg_fragment_error = -1; +static int hf_msg_reassembled_in = -1; +static int hf_msg_reassembled_length = -1; + +static gint ett_msg_fragment = -1; +static gint ett_msg_fragments = -1; static gint ett_bacapp = -1; static gint ett_bacapp_control = -1; @@ -1248,11 +3974,47 @@ static gint ett_bacapp_value = -1; static dissector_handle_t data_handle; static gint32 propertyIdentifier = -1; +static gint32 propertyArrayIndex = -1; static guint32 object_type = 4096; static guint8 bacapp_flags = 0; static guint8 bacapp_seq = 0; +static const fragment_items msg_frag_items = { + /* Fragment subtrees */ + &ett_msg_fragment, + &ett_msg_fragments, + /* Fragment fields */ + &hf_msg_fragments, + &hf_msg_fragment, + &hf_msg_fragment_overlap, + &hf_msg_fragment_overlap_conflicts, + &hf_msg_fragment_multiple_tails, + &hf_msg_fragment_too_long_fragment, + &hf_msg_fragment_error, + /* Reassembled in field */ + &hf_msg_reassembled_in, + /* Reassembled length field */ + &hf_msg_reassembled_length, + /* Tag */ + "Message fragments" +}; + +/* if BACnet uses the reserved values, then patch the corresponding values here, maximum 16 values are defined */ +static const guint MaxAPDUSize [] = { 50,128,206,480,1024,1476 }; + +static guint +fGetMaxAPDUSize(guint8 idx) +{ + /* only 16 values are defined, so use & 0x0f */ + /* check the size of the Array, deliver either the entry + or the first entry if idx is outside of the array (bug 3736 comment#7) */ + if ((idx & 0x0f) >= (gint)(sizeof(MaxAPDUSize)/sizeof(guint))) + return MaxAPDUSize[0]; + else + return MaxAPDUSize[idx & 0x0f]; +} + /* Used when there are ranges of reserved and proprietary enumerations */ static const char* val_to_split_str(guint32 val, guint32 split_val, const value_string *vs, @@ -1266,17 +4028,20 @@ val_to_split_str(guint32 val, guint32 split_val, const value_string *vs, /* from clause 20.2.1.3.2 Constructed Data */ /* returns true if the extended value is used */ -static gboolean tag_is_extended_value(guint8 tag) +static gboolean +tag_is_extended_value(guint8 tag) { return (tag & 0x07) == 5; } -static gboolean tag_is_opening(guint8 tag) +static gboolean +tag_is_opening(guint8 tag) { return (tag & 0x07) == 6; } -static gboolean tag_is_closing(guint8 tag) +static gboolean +tag_is_closing(guint8 tag) { return (tag & 0x07) == 7; } @@ -1284,22 +4049,26 @@ static gboolean tag_is_closing(guint8 tag) /* from clause 20.2.1.1 Class class bit shall be one for context specific tags */ /* returns true if the tag is context specific */ -static gboolean tag_is_context_specific(guint8 tag) +static gboolean +tag_is_context_specific(guint8 tag) { return (tag & 0x08) != 0; } -static gboolean tag_is_extended_tag_number(guint8 tag) +static gboolean +tag_is_extended_tag_number(guint8 tag) { return ((tag & 0xF0) == 0xF0); } -static guint32 object_id_type(guint32 object_identifier) +static guint32 +object_id_type(guint32 object_identifier) { return ((object_identifier >> 22) & 0x3FF); } -static guint32 object_id_instance(guint32 object_identifier) +static guint32 +object_id_instance(guint32 object_identifier) { return (object_identifier & 0x3FFFFF); } @@ -1314,7 +4083,7 @@ static gboolean fUnsigned32 (tvbuff_t *tvb, guint offset, guint32 lvt, guint32 *val) { gboolean valid = TRUE; - + switch (lvt) { case 1: *val = tvb_get_guint8(tvb, offset); @@ -1332,7 +4101,7 @@ fUnsigned32 (tvbuff_t *tvb, guint offset, guint32 lvt, guint32 *val) valid = FALSE; break; } - + return valid; } @@ -1342,7 +4111,7 @@ fUnsigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, guint64 *val) gboolean valid = FALSE; gint64 value = 0; guint8 data, i; - + if (lvt && (lvt <= 8)) { valid = TRUE; data = tvb_get_guint8(tvb, offset); @@ -1352,7 +4121,7 @@ fUnsigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, guint64 *val) } *val = value; } - + return valid; } @@ -1367,7 +4136,8 @@ fSigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, gint64 *val) { gboolean valid = FALSE; gint64 value = 0; - guint8 data, i; + guint8 data; + guint32 i; /* we can only handle 7 bytes for a 64-bit value due to signed-ness */ if (lvt && (lvt <= 7)) { @@ -1375,6 +4145,8 @@ fSigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, gint64 *val) data = tvb_get_guint8(tvb, offset); if ((data & 0x80) != 0) value = (-1 << 8) | data; + else + value = data; for (i = 1; i < lvt; i++) { data = tvb_get_guint8(tvb, offset+i); value = (value << 8) + data; @@ -1401,12 +4173,12 @@ fTagHeaderTree (tvbuff_t *tvb, proto_tree *tree, guint offset, tag = tvb_get_guint8(tvb, offset); *tag_info = 0; *lvt = tag & 0x07; - /* To solve the problem of lvt values of 6/7 being indeterminate - it */ - /* can mean open/close tag or length of 6/7 after the length is */ - /* computed below - store whole tag info, not just context bit. */ + /* To solve the problem of lvt values of 6/7 being indeterminate - it */ + /* can mean open/close tag or length of 6/7 after the length is */ + /* computed below - store whole tag info, not just context bit. */ if (tag_is_context_specific(tag)) *tag_info = tag & 0x0F; *tag_no = tag >> 4; - if (tag_is_extended_tag_number(tag)) { + if (tag_is_extended_tag_number(tag)) { *tag_no = tvb_get_guint8(tvb, offset + tag_len++); } if (tag_is_extended_value(tag)) { /* length is more than 4 Bytes */ @@ -1426,11 +4198,10 @@ fTagHeaderTree (tvbuff_t *tvb, proto_tree *tree, guint offset, } if (tree) { - if (tag_is_closing(tag) || tag_is_opening(tag)) - ti = proto_tree_add_text(tree, tvb, offset, tag_len, - "%s: %u", match_strval( - tag & 0x07, BACnetTagNames), - *tag_no); + if (tag_is_opening(tag)) + ti = proto_tree_add_text(tree, tvb, offset, tag_len, "{[%u]", *tag_no ); + else if (tag_is_closing(tag)) + ti = proto_tree_add_text(tree, tvb, offset, tag_len, "}[%u]", *tag_no ); else if (tag_is_context_specific(tag)) { ti = proto_tree_add_text(tree, tvb, offset, tag_len, "Context Tag: %u, Length/Value/Type: %u", @@ -1442,6 +4213,7 @@ fTagHeaderTree (tvbuff_t *tvb, proto_tree *tree, guint offset, BACnetApplicationTagNumber, ASHRAE_Reserved_Fmt), *lvt); + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); /* details if needed */ proto_tree_add_item(subtree, hf_BACnetTagClass, tvb, offset, 1, FALSE); @@ -1477,7 +4249,7 @@ fTagHeaderTree (tvbuff_t *tvb, proto_tree *tree, guint offset, proto_tree_add_uint(subtree, hf_bacapp_tag_lvt, tvb, lvt_offset, lvt_len, *lvt); } - + return tag_len; } @@ -1534,7 +4306,7 @@ fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) guint64 val = 0; guint8 tag_no, tag_info; guint32 lvt; - guint tag_len; + guint tag_len; proto_item *ti; proto_tree *subtree; @@ -1542,13 +4314,13 @@ fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) /* only support up to an 8 byte (64-bit) integer */ if (fUnsigned64 (tvb, offset + tag_len, lvt, &val)) ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, - "%s(Unsigned) %" PRIu64, label, val); + "%s(Unsigned) %" G_GINT64_MODIFIER "u", label, val); else ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s - %u octets (Unsigned)", label, lvt); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - + return offset+tag_len+lvt; } @@ -1569,7 +4341,7 @@ fEnumeratedTagSplit (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar if (fUnsigned32 (tvb, offset+tag_len, lvt, &val)) { if (vs) ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, - "%s %s", label, val_to_split_str(val, split_val, vs, + "%s %s", label, val_to_split_str(val, split_val, vs, ASHRAE_Reserved_Fmt,Vendor_Proprietary_Fmt)); else ti =proto_tree_add_text(tree, tvb, offset, lvt+tag_len, @@ -1586,7 +4358,7 @@ fEnumeratedTagSplit (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar static guint fEnumeratedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, - const value_string *vs) + const value_string *vs) { return fEnumeratedTagSplit (tvb, tree, offset, label, vs, 0); } @@ -1604,13 +4376,13 @@ fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (fSigned64 (tvb, offset + tag_len, lvt, &val)) ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, - "%s(Signed) %" PRId64, label, val); + "%s(Signed) %" G_GINT64_MODIFIER "d", label, val); else ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s - %u octets (Signed)", label, lvt); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - + return offset+tag_len+lvt; } @@ -1620,17 +4392,17 @@ fRealTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) guint8 tag_no, tag_info; guint32 lvt; guint tag_len; - gfloat f_val = 0.0; + gfloat f_val; proto_item *ti; proto_tree *subtree; - + tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt); f_val = tvb_get_ntohieee_float(tvb, offset+tag_len); ti = proto_tree_add_text(tree, tvb, offset, 4+tag_len, "%s%f (Real)", label, f_val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - + return offset+tag_len+4; } @@ -1640,17 +4412,17 @@ fDoubleTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) guint8 tag_no, tag_info; guint32 lvt; guint tag_len; - gdouble d_val = 0.0; + gdouble d_val; proto_item *ti; proto_tree *subtree; - + tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt); d_val = tvb_get_ntohieee_double(tvb, offset+tag_len); ti = proto_tree_add_text(tree, tvb, offset, 8+tag_len, - "%s%lf (Double)", label, d_val); + "%s%f (Double)", label, d_val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - + return offset+tag_len+8; } @@ -1665,15 +4437,15 @@ fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset) tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32 (tvb, offset+tag_len, lvt, &val)) - ti = proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, + ti = proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, offset, lvt+tag_len, val); else ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "Process Identifier - %u octets (Signed)", lvt); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); - fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - - return offset+tag_len+lvt; + offset += tag_len + lvt; + + return offset; } static guint @@ -1687,10 +4459,10 @@ fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32 (tvb, offset+tag_len, lvt, &val)) - ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, - "%s (hh.mm.ss): %d.%02d.%02d%s", - label, - (val / 3600), ((val % 3600) / 60), (val % 60), + ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, + "%s (hh.mm.ss): %d.%02d.%02d%s", + label, + (val / 3600), ((val % 3600) / 60), (val % 60), val == 0 ? " (indefinite)" : ""); else ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, @@ -1715,10 +4487,10 @@ fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset) month = tvb_get_guint8(tvb, offset+tag_len); weekOfMonth = tvb_get_guint8(tvb, offset+tag_len+1); dayOfWeek = tvb_get_guint8(tvb, offset+tag_len+2); - ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%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")); + ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%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, day_of_week, "day of week (%d) not found")); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -1754,7 +4526,7 @@ fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) months, "month (%d) not found"), day, year, val_to_str(weekday, - days, + day_of_week, "(%d) not found")); } else @@ -1762,7 +4534,7 @@ fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s%s %d, any year, (Day of Week = %s)", label, val_to_str(month, months, "month (%d) not found"), - day, val_to_str(weekday, days, "(%d) not found")); + day, val_to_str(weekday, day_of_week, "(%d) not found")); } subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -1793,11 +4565,11 @@ fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) label, hour > 12 ? hour - 12 : hour, minute, second, msec, - hour > 12 ? "P.M." : "A.M.", + hour >= 12 ? "P.M." : "A.M.", hour, minute, second, msec); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - + return offset+tag_len+lvt; } @@ -1816,20 +4588,22 @@ fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) } static guint -fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset) +fTimeValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; - guint32 lvt; + guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { /* closing Tag, but not for me */ return offset; } offset = fTime (tvb,tree,offset,"Time: "); - offset = fApplicationTypes(tvb, tree, offset, "Value: "); + offset = fApplicationTypes(tvb, pinfo, tree, offset, "Value: "); + + if (offset==lastoffset) break; /* exit loop if nothing happens inside */ } return offset; } @@ -1837,130 +4611,167 @@ fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset) static guint fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset) { - guint8 tag_no, tag_info; - guint32 lvt; + guint8 tag_no, tag_info; + guint32 lvt; switch (fTagNo(tvb, offset)) { case 0: /* Date */ offset = fDate (tvb, tree, offset, "Date: "); break; case 1: /* dateRange */ - offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateRange (tvb, tree, offset); - offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); 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) +static guint fTimeStamp (tvbuff_t *tvb, proto_tree *tree, + guint offset, const gchar *label) { guint8 tag_no = 0, tag_info = 0; guint32 lvt = 0; - if (tvb_length_remaining(tvb, offset) > 0) { /* don't loop, it's a CHOICE */ + if (tvb_reported_length_remaining(tvb, offset) > 0) { /* don't loop, it's a CHOICE */ switch (fTagNo(tvb, offset)) { case 0: /* time */ - offset = fTime (tvb, tree, offset, "timestamp: "); + offset = fTime (tvb, tree, offset, label?label:"timestamp: "); break; case 1: /* sequenceNumber */ - offset = fUnsignedTag (tvb, tree, offset, "sequence Number: "); + offset = fUnsignedTag (tvb, tree, offset, + label?label:"sequence Number: "); break; case 2: /* dateTime */ offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); - offset = fDateTime (tvb, tree, offset, "timestamp: "); + offset = fDateTime (tvb, tree, offset, label?label:"timestamp: "); offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; - break; } } + return offset; } -#if 0 + static guint -fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset) +fClientCOV (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; - - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; - - switch (fTagNo(tvb, offset)) { - case 0: /* setpointReference */ - offset = fBACnetObjectPropertyReference (tvb,tree,offset); - break; - default: - return offset; - break; - } + if (tvb_reported_length_remaining(tvb, offset) > 0) { + offset = fApplicationTypes(tvb,pinfo,tree,offset, "increment: "); } return offset; } -#endif -#if 0 -static guint -fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset) -{ - if (tvb_length_remaining(tvb, offset) > 0) { - offset = fApplicationTypes(tvb,tree,offset, "increment: "); - } - return offset; -} +static const value_string +BACnetDaysOfWeek [] = { + {0,"Monday" }, + {1,"Tuesday" }, + {2,"Wednesday" }, + {3,"Thursday" }, + {4,"Friday" }, + {5,"Saturday" }, + {6,"Sunday" }, + {0,NULL } +}; static guint -fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset) +fDestination (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - if (tvb_length_remaining(tvb, offset) > 0) { - offset = fApplicationTypesEnumerated(tvb,tree,offset, - "valid Days: ", days); + if (tvb_reported_length_remaining(tvb, offset) > 0) { + offset = fApplicationTypesEnumerated(tvb,pinfo,tree,offset, + "valid Days: ", BACnetDaysOfWeek); offset = fTime (tvb,tree,offset,"from time: "); offset = fTime (tvb,tree,offset,"to time: "); - offset = fRecipient (tvb,tree,offset); + offset = fRecipient (tvb,pinfo,tree,offset); offset = fProcessId (tvb,tree,offset); - offset = fApplicationTypes (tvb,tree,offset, + offset = fApplicationTypes (tvb,pinfo,tree,offset, "issue confirmed notifications: "); - offset = fApplicationTypesEnumerated (tvb,tree,offset, + offset = fBitStringTagVS (tvb,tree,offset, "transitions: ", BACnetEventTransitionBits); } return offset; } -#endif static guint fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, guint32 lvt) { gchar *tmp; - guint start = offset; + guint start = offset; + guint8 tag_no, tag_info; + proto_tree* subtree = tree; + proto_item* ti = 0; + + offset += fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + + if (lvt > 0) + { + tmp = tvb_bytes_to_str(tvb, offset, lvt); + ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s %s", label, tmp); + offset += lvt; + } + + if (ti) + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + + fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt); + + return offset; +} + +static guint +fMacAddress (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, guint32 lvt) +{ + gchar *tmp; + guint start = offset; guint8 tag_no, tag_info; - proto_tree* subtree = tree; - proto_item* ti = 0; + proto_tree* subtree = tree; + proto_item* ti = 0; offset += fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + ti = proto_tree_add_text(tree, tvb, offset, 6, "%s", label); /* just add the label, with the tagHeader information in its subtree */ + if (lvt > 0) - { - tmp = tvb_bytes_to_str(tvb, offset, lvt); - ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s %s", label, tmp); + { + if (lvt == 6) { /* we have 6 Byte IP Address with 4 Octets IPv4 and 2 Octets Port Information */ + + guint32 ip = tvb_get_ipv4(tvb, offset); + guint16 port = tvb_get_ntohs(tvb, offset+4); + + proto_tree_add_ipv4(tree, hf_bacapp_tag_IPV4, tvb, offset, 4, ip); + proto_tree_add_uint(tree, hf_bacapp_tag_PORT, tvb, offset+4, 2, port); + + } else { + if (lvt == 18) { /* we have 18 Byte IP Address with 16 Octets IPv6 and 2 Octets Port Information */ + struct e_in6_addr addr; + guint16 port = tvb_get_ntohs(tvb, offset+16); + tvb_get_ipv6(tvb, offset, &addr); + + proto_tree_add_ipv6(tree, hf_bacapp_tag_IPV6, tvb, offset, 16, (const guint8 *) &addr); + proto_tree_add_uint(tree, hf_bacapp_tag_PORT, tvb, offset+16, 2, port); + + } else { /* we have 1 Byte MS/TP Address or anything else interpreted as an address */ + tmp = tvb_bytes_to_str(tvb, offset, lvt); + ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s", tmp); + } + } offset += lvt; - } + } if (ti) - subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); - fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt); + fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt); return offset; } @@ -1970,29 +4781,28 @@ fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; - guint offs; + guint offs; offset = fUnsignedTag (tvb, tree, offset, "network-number"); offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (lvt == 0) { - proto_tree_add_text(tree, tvb, offset, offs, "mac-address: broadcast"); + proto_tree_add_text(tree, tvb, offset, offs, "MAC-address: broadcast"); offset += offs; } else - offset = fOctetString (tvb, tree, offset, "mac-address: ", lvt); + offset = fMacAddress (tvb, tree, offset, "MAC-address: ", lvt); + return offset; } -#if 0 static guint fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset) { offset = fOctetString (tvb,tree,offset,"session key: ", 8); return fAddress (tvb,tree,offset); } -#endif static guint -fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset) +fObjectIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; @@ -2012,6 +4822,15 @@ fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset) ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), object_id_instance(object_id)); + if (col_get_writable(pinfo->cinfo)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s,%u ", + val_to_split_str(object_type, + 128, + BACnetObjectType, + ASHRAE_Reserved_Fmt, + Vendor_Proprietary_Fmt), + object_id_instance(object_id)); + /* here are the details of how we arrived at the above text */ subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -2024,99 +4843,97 @@ fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset) } static guint -fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset) +fRecipient (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint8 tag_no, tag_info; + guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(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 */ + fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_no < 2) { + if (tag_no == 0) { /* device */ + offset = fObjectIdentifier (tvb, pinfo, tree, offset); + } + else { /* address */ + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); offset = fAddress (tvb, tree, offset); - break; - default: - return offset; - break; + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); } } return offset; } static guint -fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset) +fRecipientProcess (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; + guint8 tag_no, tag_info; + guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + switch (fTagNo(tvb, offset)) { case 0: /* recipient */ - offset = fRecipient (tvb, tree, offset); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset = fRecipient (tvb, pinfo, tree, offset); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* processId */ offset = fProcessId (tvb, tree, offset); + lastoffset = offset; break; default: - return offset; break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset) +fAddressBinding (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - offset = fObjectIdentifier (tvb, tree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); return fAddress (tvb, tree, offset); } static guint -fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset) +fActionCommand (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tag_match) { - guint lastoffset = 0; + guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; - proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + /* set the optional global properties to indicate not-used */ + propertyArrayIndex = -1; + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_is_closing(tag_info) ) { + if (tag_no == tag_match) { + return offset; + } + offset += len; subtree = tree; continue; } switch (tag_no) { - + case 0: /* deviceIdentifier */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 1: /* objectIdentifier */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 2: /* propertyIdentifier */ - offset = fPropertyIdentifier (tvb, subtree, offset); + offset = fPropertyIdentifier (tvb, pinfo, subtree, offset); break; case 3: /* propertyArrayIndex */ - offset = fUnsignedTag (tvb,subtree,offset,"Property Array Index: "); + offset = fPropertyArrayIndex (tvb, subtree, offset); break; case 4: /* propertyValue */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); - break; - } - FAULT; + offset = fPropertyValue (tvb, pinfo, subtree, offset, tag_info); break; case 5: /* priority */ offset = fUnsignedTag (tvb,subtree,offset,"Priority: "); @@ -2135,37 +4952,104 @@ fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } +/* BACnetActionList ::= SEQUENCE{ + action [0] SEQUENCE OF BACnetActionCommand + } +*/ static guint -fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset) +fActionList (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fActionCommand (tvb,tree,offset); + guint lastoffset = 0, len; + guint8 tag_no, tag_info; + guint32 lvt; + proto_tree *subtree = tree; + proto_item *ti; + + while (tvb_reported_length_remaining(tvb, offset)) { + lastoffset = offset; + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_is_closing(tag_info)) { + offset += len; + subtree = tree; + continue; + } + if (tag_is_opening(tag_info)) { + ti = proto_tree_add_text(tree, tvb, offset, 1, "Action List"); + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + offset += fTagHeaderTree (tvb, subtree, offset, + &tag_no, &tag_info, &lvt); + } + switch (tag_no) { + case 0: /* BACnetActionCommand */ + offset = fActionCommand (tvb, pinfo, subtree, offset, tag_no); + break; + default: + break; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ + } + return offset; } static guint -fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset) +fPropertyIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_item *ti; proto_tree *subtree; + const gchar *label = "Property Identifier"; propertyIdentifier = 0; /* global Variable */ tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (fUnsigned32 (tvb, offset+tag_len, lvt, (guint32 *)&propertyIdentifier)) + /* can we decode this value? */ + if (fUnsigned32 (tvb, offset+tag_len, lvt, (guint32 *)&propertyIdentifier)) { ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, - "property Identifier: %s", + "%s: %s (%u)", label, val_to_split_str(propertyIdentifier, 512, BACnetPropertyIdentifier, ASHRAE_Reserved_Fmt, - Vendor_Proprietary_Fmt)); + Vendor_Proprietary_Fmt), propertyIdentifier); + if (col_get_writable(pinfo->cinfo)) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", + val_to_split_str(propertyIdentifier, 512, + BACnetPropertyIdentifier, + ASHRAE_Reserved_Fmt, + Vendor_Proprietary_Fmt)); + } else { + /* property identifiers cannot be larger than 22-bits */ + return offset; + } + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + proto_tree_add_item(subtree, hf_BACnetPropertyIdentifier, tvb, + offset+tag_len, lvt, FALSE); + + return offset+tag_len+lvt; +} + +static guint +fPropertyArrayIndex (tvbuff_t *tvb, proto_tree *tree, guint offset) +{ + guint8 tag_no, tag_info; + guint32 lvt; + guint tag_len; + proto_item *ti; + proto_tree *subtree; + + tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (fUnsigned32 (tvb, offset + tag_len, lvt, (guint32 *)&propertyArrayIndex)) + ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, + "property Array Index (Unsigned) %u", propertyArrayIndex); else ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, - "Property Identifier - %u octets", lvt); + "property Array Index - %u octets (Unsigned)", lvt); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -2177,29 +5061,30 @@ fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *la { guint8 tag_no, tag_info, character_set; guint32 lvt, l; - size_t inbytesleft, outbytesleft = 512; + gsize inbytesleft, outbytesleft = 512; guint offs, extra = 1; guint8 *str_val; + const char *coding; guint8 bf_arr[512], *out = &bf_arr[0]; proto_item *ti; proto_tree *subtree; - guint start = offset; + guint start = offset; - if (tvb_length_remaining(tvb, offset) > 0) { + if (tvb_reported_length_remaining(tvb, offset) > 0) { offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - + character_set = tvb_get_guint8(tvb, offset+offs); - /* Account for code page if DBCS */ - if (character_set == 1) - { - extra = 3; - } - offset += (offs+extra); - lvt -= (extra); + /* Account for code page if DBCS */ + if (character_set == 1) + { + extra = 3; + } + offset += (offs+extra); + lvt -= (extra); do { - l = inbytesleft = min(lvt, 255); + inbytesleft = l = MIN(lvt, 255); /* * XXX - are we guaranteed that these encoding * names correspond, on *all* platforms with @@ -2219,41 +5104,49 @@ fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *la str_val = tvb_get_ephemeral_string(tvb, offset, l); /** this decoding may be not correct for multi-byte characters, Lka */ switch (character_set) { - case 0x00: /* ANSI_X3.4 */ + case ANSI_X34: fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ANSI_X3.4"); + coding = "ANSI X3.4"; break; - case 1: /* IBM/MICROSOFT DBCS */ + case IBM_MS_DBCS: out = str_val; + coding = "IBM MS DBCS"; break; - case 2: /* JIS C 6226 */ + case JIS_C_6226: out = str_val; + coding = "JIS C 6226"; break; - case 3: /* UCS-4 */ + case ISO_10646_UCS4: fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-4BE"); + coding = "ISO 10646 UCS-4"; break; - case 4: /* UCS-2 */ + case ISO_10646_UCS2: fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-2BE"); + coding = "ISO 10646 UCS-2"; break; - case 5: /* ISO8859-1 */ + case ISO_18859_1: fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ISO8859-1"); + coding = "ISO 8859-1"; break; default: out = str_val; + coding = "unknown"; break; } - ti = proto_tree_add_text(tree, tvb, offset, l, "%s'%s'", label, out); + ti = proto_tree_add_text(tree, tvb, offset, l, "%s%s'%s'", label, coding, out); lvt-=l; offset+=l; } while (lvt > 0); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); - fTagHeaderTree (tvb, subtree, start, &tag_no, &tag_info, &lvt); + fTagHeaderTree (tvb, subtree, start, &tag_no, &tag_info, &lvt); proto_tree_add_item(subtree, hf_BACnetCharacterSet, tvb, start+offs, 1, FALSE); - if (character_set == 1) - { - proto_tree_add_text(subtree, tvb, start+offs+1, 2, "Code Page: %d", tvb_get_ntohs(tvb, start+offs+1)); - } + + if (character_set == 1) + { + proto_tree_add_text(subtree, tvb, start+offs+1, 2, "Code Page: %d", tvb_get_ntohs(tvb, start+offs+1)); + } } return offset; } @@ -2264,14 +5157,27 @@ fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *lab { guint8 tag_no, tag_info, tmp; gint j, unused, skip; + guint start = offset; guint offs; guint32 lvt, i, numberOfBytes; guint8 bf_arr[256]; - + proto_tree* subtree = tree; + proto_item* ti = 0; + offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); numberOfBytes = lvt-1; /* Ignore byte for unused bit count */ offset+=offs; unused = tvb_get_guint8(tvb, offset); /* get the unused Bits */ + ti = proto_tree_add_text(tree, tvb, start, offs+lvt, + "%s(Bit String)", + label); + if (ti) { + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + } + fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt); + proto_tree_add_text(subtree, tvb, offset, 1, + "Unused bits: %u", + unused); skip = 0; for (i = 0; i < numberOfBytes; i++) { tmp = tvb_get_guint8(tvb, (offset)+i+1); @@ -2279,36 +5185,33 @@ fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *lab for (j = 0; j < 8-skip; j++) { if (src != NULL) { if (tmp & (1 << (7 - j))) - proto_tree_add_text(tree, tvb, + proto_tree_add_text(subtree, tvb, offset+i+1, 1, - "%s%s = TRUE", - label, + "%s = TRUE", val_to_str((guint) (i*8 +j), src, ASHRAE_Reserved_Fmt)); else - proto_tree_add_text(tree, tvb, + proto_tree_add_text(subtree, tvb, offset+i+1, 1, - "%s%s = FALSE", - label, + "%s = FALSE", val_to_str((guint) (i*8 +j), src, ASHRAE_Reserved_Fmt)); - } else { - bf_arr[min(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0'; + bf_arr[MIN(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0'; } } } if (src == NULL) { - bf_arr[min(255,numberOfBytes*8-unused)] = 0; - proto_tree_add_text(tree, tvb, offset, lvt, "%sB'%s'", label, bf_arr); + bf_arr[MIN(255,numberOfBytes*8-unused)] = 0; + proto_tree_add_text(subtree, tvb, offset, lvt, "B'%s'", bf_arr); } offset+=lvt; - + return offset; } @@ -2319,84 +5222,113 @@ fBitStringTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label } /* handles generic application types, as well as enumerated and enumerations - with reserved and proprietarty ranges (split) */ + with reserved and proprietarty ranges (split) */ static guint -fApplicationTypesEnumeratedSplit (tvbuff_t *tvb, proto_tree *tree, guint offset, +fApplicationTypesEnumeratedSplit (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *src, guint32 split_val) { guint8 tag_no, tag_info; guint32 lvt; guint tag_len; - if (tvb_length_remaining(tvb, offset) > 0) { + if (tvb_reported_length_remaining(tvb, offset) > 0) { tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - - switch (tag_no) { - case 0: /** NULL 20.2.2 */ - offset = fNullTag(tvb, tree, offset, label); - break; - case 1: /** BOOLEAN 20.2.3 */ - offset = fBooleanTag(tvb, tree, offset, label); - 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 */ - offset = fRealTag(tvb, tree, offset, label); - break; - case 5: /** Double 20.2.7 */ - offset = fDoubleTag(tvb, tree, offset, label); - break; - case 6: /** Octet String 20.2.8 */ - offset = fOctetString (tvb, tree, offset, label, lvt); - break; - case 7: /** Character String 20.2.9 */ - offset = fCharacterString (tvb,tree,offset,label); - break; - case 8: /** Bit String 20.2.10 */ - offset = fBitStringTagVS (tvb, tree, offset, label, src); - break; - case 9: /** Enumerated 20.2.11 */ - offset = fEnumeratedTagSplit (tvb, tree, offset, label, src, split_val); - 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+tag_len, "%s'reserved for ASHRAE'", label); - offset+=lvt+tag_len; - break; - default: - break; + if (!tag_is_context_specific(tag_info)) + { + switch (tag_no) { + case 0: /** NULL 20.2.2 */ + offset = fNullTag(tvb, tree, offset, label); + break; + case 1: /** BOOLEAN 20.2.3 */ + offset = fBooleanTag(tvb, tree, offset, label); + 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 */ + offset = fRealTag(tvb, tree, offset, label); + break; + case 5: /** Double 20.2.7 */ + offset = fDoubleTag(tvb, tree, offset, label); + break; + case 6: /** Octet String 20.2.8 */ + offset = fOctetString (tvb, tree, offset, label, lvt); + break; + case 7: /** Character String 20.2.9 */ + offset = fCharacterString (tvb,tree,offset,label); + break; + case 8: /** Bit String 20.2.10 */ + offset = fBitStringTagVS (tvb, tree, offset, label, src); + break; + case 9: /** Enumerated 20.2.11 */ + offset = fEnumeratedTagSplit (tvb, tree, offset, label, src, split_val); + 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, pinfo, tree, offset); + break; + case 13: /* reserved for ASHRAE */ + case 14: + case 15: + proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s'reserved for ASHRAE'", label); + offset+=lvt+tag_len; + break; + default: + break; + } + } } return offset; } static guint -fApplicationTypesEnumerated (tvbuff_t *tvb, proto_tree *tree, guint offset, +fShedLevel (tvbuff_t *tvb, proto_tree *tree, guint offset) +{ + guint lastoffset = 0; + + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; + + switch (fTagNo(tvb,offset)) { + case 0: /* percent */ + offset = fUnsignedTag (tvb, tree, offset, "shed percent: "); + break; + case 1: /* level */ + offset = fUnsignedTag (tvb, tree, offset, "shed level: "); + break; + case 2: /* amount */ + offset = fRealTag(tvb, tree, offset, "shed amount: "); + break; + default: + return offset; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ + } + return offset; +} + +static guint +fApplicationTypesEnumerated (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *vs) { - return fApplicationTypesEnumeratedSplit(tvb, tree, offset, label, vs, 0); + return fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, label, vs, 0); } static guint -fApplicationTypes (tvbuff_t *tvb, proto_tree *tree, guint offset, +fApplicationTypes (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { - return fApplicationTypesEnumeratedSplit(tvb, tree, offset, label, NULL, 0); + return fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, label, NULL, 0); } static guint @@ -2412,7 +5344,7 @@ fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar * (void)label; tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt); /* cap the the suggested length in case of bad data */ - tvb_len = tvb_length_remaining(tvb, offset+tag_len); + tvb_len = tvb_reported_length_remaining(tvb, offset+tag_len); if ((tvb_len >= 0) && ((guint32)tvb_len < lvt)) { lvt = tvb_len; @@ -2422,18 +5354,18 @@ fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar * subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - + return offset + tag_len + lvt; } static guint -fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset) +fAbstractSyntaxNType (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0, depth = 0; char ar[256]; - + if (propertyIdentifier >= 0) { g_snprintf (ar, sizeof(ar), "%s: ", @@ -2446,7 +5378,7 @@ fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset) { g_snprintf (ar, sizeof(ar), "Abstract Type: "); } - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { /* closing tag, but not for me */ @@ -2455,52 +5387,112 @@ fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset) /* Application Tags */ switch (propertyIdentifier) { - case 2: /* BACnetActionList */ - offset = fActionList (tvb,tree,offset); + case 2: /* action */ + /* loop object is application tagged, + command object is context tagged */ + if (tag_is_context_specific(tag_info)) { + /* BACnetActionList */ + offset = fActionList (tvb, pinfo, tree,offset); + } else { + /* BACnetAction */ + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar, + BACnetAction); + } break; case 30: /* BACnetAddressBinding */ - offset = fAddressBinding (tvb,tree,offset); + offset = fAddressBinding (tvb,pinfo,tree,offset); + break; + case 54: /* list of object property reference */ + offset = fLOPR (tvb, pinfo, tree,offset); + break; + case 55: /* list-of-session-keys */ + fSessionKey (tvb, tree, offset); break; case 79: /* object-type */ case 96: /* protocol-object-types-supported */ - offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, ar, + offset = fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset, ar, BACnetObjectType, 128); break; case 97: /* Protocol-Services-Supported */ - offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar, BACnetServicesSupported); break; + case 102: /* recipient-list */ + offset = fDestination (tvb, pinfo, tree, offset); + break; case 107: /* segmentation-supported */ - offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar, BACnetSegmentation); break; case 111: /* Status-Flags */ - offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar, BACnetStatusFlags); break; case 112: /* System-Status */ - offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar, BACnetDeviceStatus); break; case 117: /* units */ - offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar, BACnetEngineeringUnits); break; - case 87: /* priority-array */ - offset = fPriorityArray (tvb, tree, offset); + case 87: /* priority-array -- accessed as a BACnetARRAY */ + if (propertyArrayIndex == 0) { + /* BACnetARRAY index 0 refers to the length + of the array, not the elements of the array */ + offset = fApplicationTypes (tvb, pinfo, tree, offset, ar); + } else { + offset = fPriorityArray (tvb, pinfo, tree, offset); + } break; case 38: /* exception-schedule */ if (object_type < 128) { - offset = fSpecialEvent (tvb,tree,offset); - break; + if (propertyArrayIndex == 0) { + /* BACnetARRAY index 0 refers to the length + of the array, not the elements of the array */ + offset = fApplicationTypes (tvb, pinfo, tree, offset, ar); + } else { + offset = fSpecialEvent (tvb,pinfo,tree,offset); + } } - case 123: /* weekly-schedule */ + break; + case 19: /* controlled-variable-reference */ + case 60: /* manipulated-variable-reference */ + case 109: /* Setpoint-Reference */ + case 132: /* log-device-object-property */ + offset = fDeviceObjectPropertyReference (tvb, pinfo, tree, offset); + break; + case 123: /* weekly-schedule -- accessed as a BACnetARRAY */ if (object_type < 128) { - offset = fWeeklySchedule (tvb,tree,offset); - break; + if (propertyArrayIndex == 0) { + /* BACnetARRAY index 0 refers to the length + of the array, not the elements of the array */ + offset = fApplicationTypes (tvb, pinfo, tree, offset, ar); + } else { + offset = fWeeklySchedule (tvb, pinfo, tree, offset); + } } + break; + case 127: /* client COV increment */ + offset = fClientCOV (tvb, pinfo, tree, offset); + break; + case 131: /* log-buffer */ + offset = fLogRecord (tvb, pinfo, tree, offset); + break; + case 159: /* member-of */ + case 165: /* zone-members */ + offset = fDeviceObjectReference (tvb, pinfo, tree, offset); + break; + case 196: /* last-restart-reason */ + offset = fRestartReason (tvb, pinfo, tree, offset); + break; + case 212: /* actual-shed-level */ + case 214: /* expected-shed-level */ + case 218: /* requested-shed-level */ + offset = fShedLevel (tvb, tree, offset); + break; default: if (tag_info) { @@ -2521,51 +5513,68 @@ fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset) } else { - offset = fApplicationTypes (tvb, tree, offset, ar); + offset = fApplicationTypes (tvb, pinfo, tree, offset, ar); } break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 tagoffset) +fPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tag_info) +{ + guint8 tag_no; + guint32 lvt; + + if (tag_is_opening(tag_info)) { + offset += fTagHeaderTree(tvb, tree, offset, + &tag_no, &tag_info, &lvt); + offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset); + if (tvb_length_remaining(tvb, offset) > 0) { + offset += fTagHeaderTree(tvb, tree, offset, + &tag_no, &tag_info, &lvt); + } + } else { + proto_tree_add_text(tree, tvb, offset, tvb_length(tvb) - offset, + "expected Opening Tag!"); \ + offset = tvb_length(tvb); + } + + return offset; +} + + +static guint +fPropertyIdentifierValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset) { guint lastoffset = offset; - proto_item *tt; - proto_tree *subtree; guint8 tag_no, tag_info; guint32 lvt; - - offset = fPropertyReference(tvb, tree, offset, tagoffset, 0); + + offset = fPropertyReference(tvb, pinfo, tree, offset, tagoffset, 0); if (offset > lastoffset) { fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_no == tagoffset+2) { /* Value - might not be present in ReadAccessResult */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(tree, tvb, offset, 1, "propertyValue"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); - offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - } + offset = fPropertyValue (tvb, pinfo, tree, offset, tag_info); } } return offset; } static guint -fBACnetPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset) +fBACnetPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - offset = fPropertyValue(tvb, tree, offset, 0); + offset = fPropertyIdentifierValue(tvb, pinfo, tree, offset, 0); if (offset > lastoffset) { /* detect optional priority @@ -2574,24 +5583,35 @@ fBACnetPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset) if (tag_is_context_specific(tag_info) && (tag_no == 3)) offset = fUnsignedTag (tvb,tree,offset,"Priority: "); } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fSubscribeCOVPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint lastoffset = 0, len; + guint8 tag_no, tag_info; + guint32 lvt; + proto_tree *subtree = tree; + proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - - switch (fTagNo(tvb,offset)) { + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_is_closing(tag_info)) { + offset += len; + subtree = tree; + continue; + } + + switch (tag_no) { case 0: /* ProcessId */ offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: "); break; case 1: /* monitored ObjectId */ - offset = fObjectIdentifier (tvb, tree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 2: /* issueConfirmedNotifications */ offset = fBooleanTag (tvb, tree, offset, "issue Confirmed Notifications: "); @@ -2600,33 +5620,42 @@ fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) offset = fTimeSpan (tvb,tree,offset,"life time"); break; case 4: /* monitoredPropertyIdentifier */ - offset = fBACnetPropertyReference (tvb, tree, offset, 0); + if (tag_is_opening(tag_info)) { + tt = proto_tree_add_text(subtree, tvb, offset, 1, "monitoredPropertyIdentifier"); + if (tt) { + subtree = proto_item_add_subtree(tt, ett_bacapp_value); + } + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fBACnetPropertyReference (tvb, pinfo, subtree, offset, 1); + break; + } + FAULT; break; case 5: /* covIncrement */ offset = fRealTag (tvb, tree, offset, "COV Increment: "); break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fSubscribeCOVRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fSubscribeCOVPropertyRequest(tvb, tree, offset); + return fSubscribeCOVPropertyRequest(tvb, pinfo, tree, offset); } static guint -fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset) +fWhoHas (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + switch (fTagNo(tvb, offset)) { case 0: /* deviceInstanceLowLimit */ offset = fUnsignedTag (tvb, tree, offset, "device Instance Low Limit: "); @@ -2635,31 +5664,32 @@ fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset) offset = fUnsignedTag (tvb, tree, offset, "device Instance High Limit: "); break; case 2: /* BACnetObjectId */ - offset = fObjectIdentifier (tvb, tree, offset); - break; + offset = fObjectIdentifier (tvb, pinfo, tree, offset); + break; case 3: /* messageText */ offset = fCharacterString (tvb,tree,offset, "Object Name: "); break; default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset) +fDailySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info) && tag_no == 0) { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); /* opening context tag 0 */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { @@ -2667,8 +5697,9 @@ fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset) offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); return offset; } - - offset = fTimeValue (tvb, subtree, offset); + + offset = fTimeValue (tvb, pinfo, subtree, offset); + if (offset == lastoffset) break; /* nothing happened, exit loop */ } } else if (tag_no == 0 && lvt == 0) @@ -2680,24 +5711,35 @@ fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset) } static guint -fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset) +fWeeklySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - guint i=1; + guint i = 1; /* day of week array index */ proto_tree *subtree = tree; proto_item *tt; - - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + + if (propertyArrayIndex > 0) { + /* BACnetARRAY index 0 refers to the length + of the array, not the elements of the array. + BACnetARRAY index -1 is our internal flag that + the optional index was not used. + BACnetARRAY refers to this as all elements of the array. + If the optional index is specified for a BACnetARRAY, + then that specific array element is referenced. */ + i = propertyArrayIndex; + } + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; /* outer encoding will print out closing tag */ } - tt = proto_tree_add_text(tree, tvb, offset, 0, val_to_str(i++, days, "day of week (%d) not found")); + tt = proto_tree_add_text(tree, tvb, offset, 0, "%s", val_to_str(i++, day_of_week, "day of week (%d) not found")); subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset = fDailySchedule (tvb,subtree,offset); + offset = fDailySchedule (tvb, pinfo, subtree, offset); + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } @@ -2706,16 +5748,16 @@ fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset) static guint fUTCTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) { - if (tvb_length_remaining(tvb, offset) <= 0) + if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; - + return fDateTime (tvb, tree, offset, "UTC-Time: "); } static guint fTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) { - if (tvb_length_remaining(tvb, offset) <= 0) + if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; return fDateTime (tvb, tree, offset, NULL); @@ -2724,23 +5766,95 @@ fTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) static guint fDateRange (tvbuff_t *tvb, proto_tree *tree, guint offset) { - if (tvb_length_remaining(tvb, offset) <= 0) + if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; - offset = fDate (tvb,tree,offset,"Start Date: "); + 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) +fVendorIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) +{ + guint32 val = 0; + guint8 tag_no, tag_info; + guint32 lvt; + guint tag_len; + proto_item *ti; + proto_tree *subtree; + const gchar *label = "Vendor ID"; + + tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (fUnsigned32 (tvb, offset + tag_len, lvt, &val)) + ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, + "%s: %s (%u)", label, + val_to_str(val,BACnetVendorIdentifiers,"Unknown Vendor"), val); + else + ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, + "%s - %u octets (Unsigned)", label, lvt); + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + + if ((lvt < 1) || (lvt > 2)) { /* vendorIDs >= 1 and <= 2 are supported */ + proto_item *expert_item; + expert_item = proto_tree_add_text(tree, tvb, 0, lvt, "Wrong length indicated. Expected 1 or 2, got %u", lvt); + expert_add_info_format(pinfo, expert_item, PI_MALFORMED, PI_ERROR, "Wrong length indicated. Expected 1 or 2, got %u", lvt); + PROTO_ITEM_SET_GENERATED(expert_item); + return offset+tag_len+lvt; + } + + proto_tree_add_item(subtree, hf_BACnetVendorIdentifier, tvb, + offset+tag_len, lvt, FALSE); + + return offset+tag_len+lvt; +} + +static guint +fRestartReason (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) +{ + guint32 val = 0; + guint8 tag_no, tag_info; + guint32 lvt; + guint tag_len; + proto_item *ti; + proto_tree *subtree; + const gchar *label = "Restart Reason"; + + tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (fUnsigned32 (tvb, offset + tag_len, lvt, &val)) + ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, + "%s: %s (%u)", label, + val_to_str(val,BACnetRestartReason,"Unknown reason"), val); + else + ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, + "%s - %u octets (Unsigned)", label, lvt); + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + + if (lvt != 1) { + proto_item *expert_item; + expert_item = proto_tree_add_text(tree, tvb, 0, lvt, "Wrong length indicated. Expected 1, got %u", lvt); + expert_add_info_format(pinfo, expert_item, PI_MALFORMED, PI_ERROR, "Wrong length indicated. Expected 1, got %u", lvt); + PROTO_ITEM_SET_GENERATED(expert_item); + return offset+tag_len+lvt; + } + + proto_tree_add_item(subtree, hf_BACnetRestartReason, tvb, + offset+tag_len, lvt, FALSE); + + return offset+tag_len+lvt; +} + +static guint +fConfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* textMessageSourceDevice */ - offset = fObjectIdentifier (tvb, tree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 1: /* messageClass */ switch (fTagNo(tvb, offset)) { @@ -2761,36 +5875,35 @@ fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fUnconfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fConfirmedTextMessageRequest(tvb, tree, offset); + return fConfirmedTextMessageRequest(tvb, pinfo, tree, offset); } static guint -fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fConfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; proto_item *tt; - /* exit loop if nothing happens inside */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { + /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { if (tag_no == 2) /* Make sure it's the expected tag */ { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); + offset += len; subtree = tree; continue; } @@ -2802,7 +5915,7 @@ fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) switch (tag_no) { case 0: /* vendorID */ - offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: "); + offset = fVendorIdentifier (tvb, pinfo, subtree, offset); break; case 1: /* serviceNumber */ offset = fUnsignedTag (tvb, subtree, offset, "service Number: "); @@ -2812,7 +5925,7 @@ fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters"); subtree = proto_item_add_subtree(tt, ett_bacapp_value); propertyIdentifier = -1; - offset = fAbstractSyntaxNType (tvb, subtree, offset); + offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset); break; } FAULT; @@ -2820,24 +5933,25 @@ fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fConfirmedPrivateTransferRequest(tvb, tree, offset); + return fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset); } static guint -fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset) +fConfirmedPrivateTransferAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fConfirmedPrivateTransferRequest(tvb, tree, offset); + return fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset); } static guint -fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label) +fLifeSafetyOperationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint lastoffset = 0; guint8 tag_no, tag_info; @@ -2850,10 +5964,10 @@ fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, const subtree = proto_item_add_subtree(tt, ett_bacapp_value); } - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - + switch (tag_no) { case 0: /* subscriberProcessId */ offset = fUnsignedTag (tvb, subtree, offset, "requesting Process Id: "); @@ -2862,21 +5976,22 @@ fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, const offset = fCharacterString (tvb, tree, offset, "requesting Source: "); break; case 2: /* request */ - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "request: ", BACnetLifeSafetyOperation, 64); break; case 3: /* objectId */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } -static guint fBACnetPropertyStates(tvbuff_t *tvb, proto_tree *tree, guint offset) +static guint +fBACnetPropertyStates(tvbuff_t *tvb, proto_tree *tree, guint offset) { switch (fTagNo(tvb, offset)) { @@ -2884,54 +5999,54 @@ static guint fBACnetPropertyStates(tvbuff_t *tvb, proto_tree *tree, guint offset offset = fBooleanTag (tvb, tree, offset, "boolean-value: "); break; case 1: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "binary-value: ", BACnetBinaryPV, 2); break; case 2: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "event-type: ", BACnetEventType, 12); break; case 3: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "polarity: ", BACnetPolarity, 2); break; case 4: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "program-change: ", BACnetProgramRequest, 5); break; case 5: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "program-state: ", BACnetProgramState, 5); break; case 6: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "reason-for-halt: ", BACnetProgramError, 5); break; case 7: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "reliability: ", BACnetReliability, 10); break; case 8: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "state: ", BACnetEventState, 64); break; case 9: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "system-status: ", BACnetDeviceStatus, 64); break; case 10: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "units: ", BACnetEngineeringUnits, 2); break; case 11: offset = fUnsignedTag(tvb, tree, offset, "unsigned-value: "); break; case 12: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "life-safety-mode: ", BACnetLifeSafetyMode, 64); break; case 13: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "life-safety-state: ", BACnetLifeSafetyState, 64); break; default: @@ -2940,8 +6055,106 @@ static guint fBACnetPropertyStates(tvbuff_t *tvb, proto_tree *tree, guint offset return offset; } + +/* +BACnetDeviceObjectPropertyValue ::= SEQUENCE { + deviceIdentifier [0] BACnetObjectIdentifier, + objectIdentifier [1] BACnetObjectIdentifier, + propertyIdentifier [2] BACnetPropertyIdentifier, + arrayIndex [3] Unsigned OPTIONAL, + value [4] ABSTRACT-SYNTAX.&Type + } +*/ +static guint +fDeviceObjectPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) +{ + guint lastoffset = 0; + guint8 tag_no, tag_info; + guint32 lvt; + + while (tvb_reported_length_remaining(tvb, offset)) { + lastoffset = offset; + /* check the tag. A closing tag means we are done */ + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_is_closing(tag_info)) { + return offset; + } + switch (tag_no) { + case 0: /* deviceIdentifier */ + offset = fObjectIdentifier (tvb, pinfo, tree, offset); + break; + case 1: /* objectIdentifier */ + offset = fObjectIdentifier (tvb, pinfo, tree, offset); + break; + case 2: /* propertyIdentifier */ + offset = fPropertyIdentifier (tvb, pinfo, tree, offset); + break; + case 3: /* arrayIndex - OPTIONAL */ + offset = fUnsignedTag (tvb, tree, offset, + "arrayIndex: "); + break; + case 4: /* value */ + offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset); + offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); + break; + default: + return offset; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ + } + return offset; +} + + +/* +BACnetDeviceObjectPropertyReference ::= SEQUENCE { + objectIdentifier [0] BACnetObjectIdentifier, + propertyIdentifier [1] BACnetPropertyIdentifier, + propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype + -- if omitted with an array then + -- the entire array is referenced + deviceIdentifier [3] BACnetObjectIdentifier OPTIONAL + } +*/ +static guint +fDeviceObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) +{ + guint lastoffset = 0; + guint8 tag_no, tag_info; + guint32 lvt; + + while (tvb_reported_length_remaining(tvb, offset)) { + lastoffset = offset; + /* check the tag. A closing tag means we are done */ + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_is_closing(tag_info)) { + return offset; + } + switch (tag_no) { + case 0: /* objectIdentifier */ + offset = fObjectIdentifier (tvb, pinfo, tree, offset); + break; + case 1: /* propertyIdentifier */ + offset = fPropertyIdentifier (tvb, pinfo, tree, offset); + break; + case 2: /* arrayIndex - OPTIONAL */ + offset = fUnsignedTag (tvb, tree, offset, + "arrayIndex: "); + break; + case 3: /* deviceIdentifier - OPTIONAL */ + offset = fObjectIdentifier (tvb, pinfo, tree, offset); + break; + default: + return offset; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ + } + return offset; +} + static guint -fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset) +fNotificationParameters (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = offset; guint8 tag_no, tag_info; @@ -2949,61 +6162,66 @@ fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset) proto_tree *subtree = tree; proto_item *tt; - tt = proto_tree_add_text(subtree, tvb, offset, 0, "notification parameters"); + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + tt = proto_tree_add_text(subtree, tvb, offset, 0, "notification parameters (%d) %s", + tag_no, val_to_str(tag_no, BACnetEventType, "invalid type")); subtree = proto_item_add_subtree(tt, ett_bacapp_value); - /* Opeing tag for parameter choice */ + /* Opening tag for parameter choice */ offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* change-of-bitstring */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: - offset = fBitStringTag (tvb, subtree, offset, + offset = fBitStringTag (tvb, subtree, offset, "referenced-bitstring: "); break; case 1: - offset = fEnumeratedTag (tvb, subtree, offset, + offset = fBitStringTagVS (tvb, subtree, offset, "status-flags: ", BACnetStatusFlags); + lastoffset = offset; break; default: - return offset; break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } break; case 1: /* change-of-state */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyStates(tvb, subtree, offset); offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + break; case 1: - offset = fEnumeratedTag (tvb, subtree, offset, + offset = fBitStringTagVS (tvb, subtree, offset, "status-flags: ", BACnetStatusFlags); lastoffset = offset; break; default: break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } break; - case 2: /* change-of-value */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + case 2: /* change-of-value */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: - offset = fBitStringTag (tvb, subtree, offset, + offset = fBitStringTag (tvb, subtree, offset, "changed-bits: "); break; case 1: - offset = fRealTag (tvb, subtree, offset, + offset = fRealTag (tvb, subtree, offset, "changed-value: "); break; default: @@ -3012,44 +6230,54 @@ fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset) offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: - offset = fEnumeratedTag (tvb, subtree, offset, + offset = fBitStringTagVS (tvb, subtree, offset, "status-flags: ", BACnetStatusFlags); + lastoffset = offset; break; default: break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } break; - case 3: /* command-failure */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + case 3: /* command-failure */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* "command-value: " */ + /* from BACnet Table 13-3, + Standard Object Property Values Returned in Notifications */ + propertyIdentifier = 85; /* PRESENT_VALUE */ offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); + offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: - offset = fEnumeratedTag (tvb, subtree, offset, + offset = fBitStringTagVS (tvb, subtree, offset, "status-flags: ", BACnetStatusFlags); + break; case 2: /* "feedback-value: " */ + propertyIdentifier = 40; /* FEEDBACK_VALUE */ offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); + offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + lastoffset = offset; + break; default: break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } break; - case 4: /* floating-limit */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + case 4: /* floating-limit */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fRealTag (tvb, subtree, offset, "reference-value: "); break; case 1: - offset = fEnumeratedTag (tvb, subtree, offset, + offset = fBitStringTagVS (tvb, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: @@ -3057,20 +6285,23 @@ fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset) break; case 3: offset = fRealTag (tvb, subtree, offset, "error-limit: "); + lastoffset = offset; + break; default: break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } break; - case 5: /* out-of-range */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + case 5: /* out-of-range */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fRealTag (tvb, subtree, offset, "exceeding-value: "); break; case 1: - offset = fEnumeratedTag (tvb, subtree, offset, + offset = fBitStringTagVS (tvb, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: @@ -3078,26 +6309,30 @@ fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset) break; case 3: offset = fRealTag (tvb, subtree, offset, "exceeded-limit: "); + lastoffset = offset; + break; default: break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } break; case 6: - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; - offset =fBACnetPropertyValue (tvb,subtree,offset); + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; + offset =fBACnetPropertyValue (tvb,pinfo,subtree,offset); + if (offset == lastoffset) break; /* nothing happened, exit loop */ } break; case 7: /* buffer-ready */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: - offset = fObjectIdentifier (tvb, subtree, offset); /* buffer-device */ + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); /* buffer-device */ break; case 1: - offset = fObjectIdentifier (tvb, subtree, offset); /* buffer-object */ + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); /* buffer-object */ break; case 2: offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -3108,38 +6343,116 @@ fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset) offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime (tvb, subtree, offset, "current-notification: "); offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + lastoffset = offset; + break; default: break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } break; - case 8: /* change-of-life-safety */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + case 8: /* change-of-life-safety */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: - offset = fEnumeratedTagSplit (tvb, subtree, offset, + offset = fEnumeratedTagSplit (tvb, subtree, offset, "new-state: ", BACnetLifeSafetyState, 256); break; case 1: - offset = fEnumeratedTagSplit (tvb, subtree, offset, - "new-mode: ", BACnetLifeSafetyState, 256); + offset = fEnumeratedTagSplit (tvb, subtree, offset, + "new-mode: ", BACnetLifeSafetyMode, 256); break; case 2: - offset = fEnumeratedTag (tvb, subtree, offset, + offset = fBitStringTagVS (tvb, subtree, offset, "status-flags: ", BACnetStatusFlags); + break; case 3: - offset = fEnumeratedTagSplit (tvb, subtree, offset, + offset = fEnumeratedTagSplit (tvb, subtree, offset, "operation-expected: ", BACnetLifeSafetyOperation, 64); + lastoffset = offset; + break; default: - return offset; break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } - break; + break; + case 9: /* extended */ + while (tvb_reported_length_remaining(tvb, offset)) { + lastoffset = offset; + switch (fTagNo(tvb, offset)) { + case 0: + offset = fVendorIdentifier (tvb, pinfo, subtree, offset); + break; + case 1: + offset = fUnsignedTag (tvb, subtree, offset, + "extended-event-type: "); + break; + case 2: /* parameters */ + offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fApplicationTypes(tvb, pinfo, subtree, offset, "parameters: "); + offset = fDeviceObjectPropertyValue(tvb, pinfo, subtree, offset); + offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + lastoffset = offset; + break; + default: + break; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ + } + break; + case 10: /* buffer ready */ + while (tvb_reported_length_remaining(tvb, offset)) { + lastoffset = offset; + switch (fTagNo(tvb, offset)) { + case 0: /* buffer-property */ + offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fDeviceObjectPropertyReference (tvb, pinfo, subtree, offset); + offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + break; + case 1: + offset = fUnsignedTag (tvb, subtree, offset, + "previous-notification: "); + break; + case 2: + offset = fUnsignedTag (tvb, subtree, offset, + "current-notification: "); + lastoffset = offset; + break; + default: + break; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ + } + break; + case 11: /* unsigned range */ + while (tvb_reported_length_remaining(tvb, offset)) { + lastoffset = offset; + switch (fTagNo(tvb, offset)) { + case 0: + offset = fUnsignedTag (tvb, subtree, offset, + "exceeding-value: "); + break; + case 1: + offset = fBitStringTagVS (tvb, subtree, offset, + "status-flags: ", BACnetStatusFlags); + break; + case 2: + offset = fUnsignedTag (tvb, subtree, offset, + "exceeded-limit: "); + lastoffset = offset; + break; + default: + break; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ + } + break; default: break; } + /* Closing tag for parameter choice */ offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); @@ -3152,11 +6465,11 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* change-of-bitstring */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: @@ -3173,16 +6486,16 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) return offset; } } - break; + break; case 1: /* change-of-state */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(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: /* SEQUENCE OF BACnetPropertyStates */ - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "value: ", BACnetPropertyStates, 64); break; default: @@ -3190,9 +6503,9 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) } } break; - case 2: /* change-of-value */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + case 2: /* change-of-value */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fTimeSpan (tvb, tree, offset, "Time Delay"); @@ -3203,7 +6516,7 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) offset = fBitStringTag (tvb, tree, offset, "bitmask: "); break; case 1: - offset = fRealTag (tvb, tree, offset, + offset = fRealTag (tvb, tree, offset, "referenced Property Increment: "); break; default: @@ -3213,30 +6526,30 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) return offset; } } - break; - case 3: /* command-failure */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + break; + case 3: /* command-failure */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(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); + offset = fDeviceObjectPropertyReference (tvb,pinfo,tree,offset); default: return offset; } } - break; - case 4: /* floating-limit */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + break; + case 4: /* floating-limit */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(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); + offset = fDeviceObjectPropertyReference (tvb,pinfo,tree,offset); break; case 2: offset = fRealTag (tvb, tree, offset, "low diff limit: "); @@ -3253,7 +6566,7 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) } break; case 5: /* out-of-range */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: @@ -3272,12 +6585,12 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) return offset; } } - break; + break; case 6: - offset = fBACnetPropertyValue (tvb,tree,offset); + offset = fBACnetPropertyValue (tvb,pinfo,tree,offset); break; case 7: /* buffer-ready */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: @@ -3291,24 +6604,24 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) return offset; } } - break; + break; case 8: /* change-of-life-safety */ - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(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 = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "life safety alarm value: ", BACnetLifeSafetyState, 256); break; case 2: - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "alarm value: ", BACnetLifeSafetyState, 256); break; case 3: - offset = fDeviceObjectPropertyReference (tvb, tree, offset); + offset = fDeviceObjectPropertyReference (tvb, pinfo, tree, offset); break; default: return offset; @@ -3321,22 +6634,29 @@ fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset) } return offset; } +#endif static guint -fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset) +fLogRecord (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; + guint8 tag_no, tag_info; + guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* timestamp */ - offset = fDateTime (tvb,tree,offset,NULL); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset = fDate (tvb,tree,offset,"Date: "); + offset = fTime (tvb,tree,offset,"Time: "); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* logDatum: don't loop, it's a CHOICE */ + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: /* logStatus */ - offset = fEnumeratedTag (tvb, tree, offset, + offset = fEnumeratedTag (tvb, tree, offset, "log status: ", BACnetLogStatus); break; case 1: @@ -3361,53 +6681,57 @@ fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset) offset = fNullTag(tvb, tree, offset, "null value: "); break; case 8: - offset = fError (tvb,tree,offset); + offset = fError (tvb, pinfo, tree, offset); break; case 9: offset = fRealTag (tvb, tree, offset, "time change: "); break; case 10: /* any Value */ - offset = fAbstractSyntaxNType (tvb, tree, offset); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } - break; + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); + break; case 2: - offset = fEnumeratedTag (tvb, tree, offset, - "status Flags: ", BACnetStatusFlags); + offset = fEnumeratedTag (tvb, tree, offset, + "Status Flags: ", BACnetStatusFlags); break; default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } -#endif + static guint -fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fConfirmedEventNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* 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); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 2: /* event ObjectId */ - offset = fObjectIdentifier (tvb, tree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 3: /* time stamp */ offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); - offset = fTimeStamp (tvb, tree, offset); + offset = fTimeStamp (tvb, tree, offset, NULL); offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* notificationClass */ @@ -3417,7 +6741,7 @@ fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offse offset = fUnsignedTag (tvb, tree, offset, "Priority: "); break; case 6: /* EventType */ - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "Event Type: ", BACnetEventType, 64); break; case 7: /* messageText */ @@ -3431,59 +6755,59 @@ fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offse offset = fBooleanTag (tvb, tree, offset, "ack Required: "); break; case 10: /* fromState */ - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "from State: ", BACnetEventState, 64); break; case 11: /* toState */ - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "to State: ", BACnetEventState, 64); break; case 12: /* NotificationParameters */ offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); - offset = fNotificationParameters (tvb, tree, offset); + offset = fNotificationParameters (tvb, pinfo, tree, offset); offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; default: break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fConfirmedEventNotificationRequest (tvb, tree, offset); + return fConfirmedEventNotificationRequest (tvb, pinfo, tree, offset); } static guint -fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fConfirmedCOVNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_is_closing(tag_info)) { + offset += len; subtree = tree; continue; } - + switch (tag_no) { case 0: /* ProcessId */ offset = fProcessId (tvb,tree,offset); break; - case 1: /* initiating ObjectId */ - offset = fObjectIdentifier (tvb, subtree, offset); + case 1: /* initiating DeviceId */ + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 2: /* monitored ObjectId */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 3: /* time remaining */ offset = fTimeSpan (tvb, tree, offset, "Time remaining"); @@ -3493,48 +6817,48 @@ fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values"); subtree = proto_item_add_subtree(tt, ett_bacapp_value); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fBACnetPropertyValue (tvb, subtree, offset); + offset = fBACnetPropertyValue (tvb, pinfo, subtree, offset); break; } FAULT; break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fConfirmedCOVNotificationRequest (tvb, tree, offset); + return fConfirmedCOVNotificationRequest (tvb, pinfo, tree, offset); } static guint -fAcknowledgeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fAcknowledgeAlarmRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no = 0, tag_info = 0; guint32 lvt = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* 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); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 2: /* eventStateAcknowledged */ - offset = fEnumeratedTagSplit (tvb, tree, offset, + offset = fEnumeratedTagSplit (tvb, tree, offset, "event State Acknowledged: ", BACnetEventState, 64); break; case 3: /* timeStamp */ offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); - offset = fTimeStamp(tvb, tree, offset); + offset = fTimeStamp(tvb, tree, offset, NULL); offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* acknowledgementSource */ @@ -3542,227 +6866,268 @@ fAcknowledgeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) break; case 5: /* timeOfAcknowledgement */ offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); - offset = fTimeStamp(tvb, tree, offset); + offset = fTimeStamp(tvb, tree, offset, "acknowledgement timestamp: "); offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fGetAlarmSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fGetAlarmSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: "); - offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, + offset = fApplicationTypes (tvb, pinfo, tree, offset, "Object Identifier: "); + offset = fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset, "alarm State: ", BACnetEventState, 64); - offset = fApplicationTypesEnumerated (tvb, tree, offset, + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, "acknowledged Transitions: ", BACnetEventTransitionBits); + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fGetEnrollmentSummaryRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fGetEnrollmentSummaryRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* acknowledgmentFilter */ - offset = fEnumeratedTag (tvb, tree, offset, + offset = fEnumeratedTag (tvb, tree, offset, "acknowledgment Filter: ", BACnetAcknowledgementFilter); break; - case 1: /* eventObjectId */ + case 1: /* eventObjectId - OPTIONAL */ + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset = fRecipientProcess (tvb, pinfo, tree, offset); offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); - offset = fRecipientProcess (tvb, tree, offset); break; case 2: /* eventStateFilter */ - offset = fEnumeratedTag (tvb, tree, offset, + offset = fEnumeratedTag (tvb, tree, offset, "event State Filter: ", BACnetEventStateFilter); break; - case 3: /* eventTypeFilter */ - offset = fEnumeratedTag (tvb, tree, offset, + case 3: /* eventTypeFilter - OPTIONAL */ + offset = fEnumeratedTag (tvb, tree, offset, "event Type Filter: ", BACnetEventType); break; case 4: /* priorityFilter */ + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); offset = fUnsignedTag (tvb, tree, offset, "min Priority: "); offset = fUnsignedTag (tvb, tree, offset, "max Priority: "); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; - case 5: /* notificationClassFilter */ + case 5: /* notificationClassFilter - OPTIONAL */ offset = fUnsignedTag (tvb, tree, offset, "notification Class Filter: "); break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fGetEnrollmentSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fGetEnrollmentSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: "); - offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, + offset = fApplicationTypes (tvb, pinfo, tree, offset, "Object Identifier: "); + offset = fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset, "event Type: ", BACnetEventType, 64); - offset = fApplicationTypesEnumerated (tvb, tree, offset, - "event State: ", BACnetEventStateFilter); - offset = fApplicationTypes (tvb, tree, offset, "Priority: "); - offset = fApplicationTypes (tvb, tree, offset, "Notification Class: "); + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, + "event State: ", BACnetEventState); + offset = fApplicationTypes (tvb, pinfo, tree, offset, "Priority: "); + offset = fApplicationTypes (tvb, pinfo, tree, offset, "Notification Class: "); + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fGetEventInformationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fGetEventInformationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; - - while ((tvb_length_remaining(tvb, offset) > 0)&&(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; + if (tvb_reported_length_remaining(tvb, offset) > 0) { + if (fTagNo(tvb, offset) == 0) { + offset = fObjectIdentifier (tvb, pinfo, tree, offset); } } return offset; } static guint -flistOfEventSummaries (tvbuff_t *tvb, proto_tree *tree, guint offset) +flistOfEventSummaries (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; + guint8 tag_no, tag_info; + guint32 lvt; + proto_tree* subtree = tree; + proto_item* ti = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - switch (fTagNo(tvb, offset)) { + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + /* we are finished here if we spot a closing tag */ + if (tag_is_closing(tag_info)) { + break; + } + switch (tag_no) { case 0: /* ObjectId */ - offset = fObjectIdentifier (tvb, tree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 1: /* eventState */ - offset = fEnumeratedTag (tvb, tree, offset, - "event State: ", BACnetEventStateFilter); + offset = fEnumeratedTag (tvb, tree, offset, + "event State: ", BACnetEventState); break; case 2: /* acknowledgedTransitions */ - offset = fEnumeratedTag (tvb, tree, offset, + offset = fBitStringTagVS (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: "); + ti = proto_tree_add_text(tree, tvb, offset, lvt, "eventTimeStamps"); + if (ti) { + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + } + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fTimeStamp (tvb, subtree, offset,"TO-OFFNORMAL timestamp: "); + offset = fTimeStamp (tvb, subtree, offset,"TO-FAULT timestamp: "); + offset = fTimeStamp (tvb, subtree, offset,"TO-NORMAL timestamp: "); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* notifyType */ - offset = fEnumeratedTag (tvb, tree, offset, + offset = fEnumeratedTag (tvb, tree, offset, "Notify Type: ", BACnetNotifyType); break; case 5: /* eventEnable */ - offset = fEnumeratedTag (tvb, tree, offset, + offset = fBitStringTagVS (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: "); + ti = proto_tree_add_text(tree, tvb, offset, lvt, "eventPriorities"); + if (ti) { + subtree = proto_item_add_subtree(ti, ett_bacapp_tag); + } + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fUnsignedTag (tvb, subtree, offset, "TO-OFFNORMAL Priority: "); + offset = fUnsignedTag (tvb, subtree, offset, "TO-FAULT Priority: "); + offset = fUnsignedTag (tvb, subtree, offset, "TO-NORMAL Priority: "); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ + } + return offset; +} + +static guint +fLOPR (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) +{ + guint lastoffset = 0; + guint8 tag_no, tag_info; + guint32 lvt; + + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ + lastoffset = offset; + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + /* we are finished here if we spot a closing tag */ + if (tag_is_closing(tag_info)) { break; } + offset = fDeviceObjectPropertyReference(tvb, pinfo, tree, offset); + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fGetEventInformationACK (tvbuff_t *tvb, proto_tree *tree, guint offset) +fGetEventInformationACK (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* listOfEventSummaries */ offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); - offset = flistOfEventSummaries (tvb, tree, offset); + offset = flistOfEventSummaries (tvb, pinfo, tree, offset); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* moreEvents */ offset = fBooleanTag (tvb, tree, offset, "more Events: "); break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fAddListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fAddListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ + + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); + offset += len; subtree = tree; continue; } - + switch (tag_no) { case 0: /* ObjectId */ - offset = fBACnetObjectPropertyReference (tvb, subtree, offset); + offset = fBACnetObjectPropertyReference (tvb, pinfo, subtree, offset); break; case 3: /* listOfElements */ if (tag_is_opening(tag_info)) { tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfElements"); subtree = proto_item_add_subtree(tt, ett_bacapp_value); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); + offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset); break; } FAULT; break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fDeleteObjectRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fDeleteObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fObjectIdentifier (tvb, tree, offset); + return fObjectIdentifier (tvb, pinfo, tree, offset); } static guint @@ -3770,9 +7135,9 @@ fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + switch (fTagNo(tvb, offset)) { case 0: /* timeDuration */ offset = fUnsignedTag (tvb,tree,offset,"time Duration: "); @@ -3781,13 +7146,13 @@ fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset offset = fEnumeratedTag (tvb, tree, offset, "enable-disable: ", BACnetEnableDisable); break; - case 2: /* password */ + case 2: /* password - OPTIONAL */ offset = fCharacterString (tvb, tree, offset, "Password: "); break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } @@ -3797,58 +7162,59 @@ fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + switch (fTagNo(tvb, offset)) { case 0: /* reinitializedStateOfDevice */ - offset = fEnumeratedTag (tvb, tree, offset, - "reinitialized State Of Device: ", + offset = fEnumeratedTag (tvb, tree, offset, + "reinitialized State Of Device: ", BACnetReinitializedStateOfDevice); break; - case 1: /* password */ + case 1: /* password - OPTIONAL */ offset = fCharacterString (tvb, tree, offset, "Password: "); break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fVtOpenRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fVtOpenRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - offset = fApplicationTypesEnumerated (tvb, tree, offset, + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, "vtClass: ", BACnetVTClass); - return fApplicationTypes (tvb,tree,offset,"local VT Session ID: "); + return fApplicationTypes (tvb, pinfo, tree,offset,"local VT Session ID: "); } static guint -fVtOpenAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fVtOpenAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fApplicationTypes (tvb,tree,offset,"remote VT Session ID: "); + return fApplicationTypes (tvb, pinfo, tree,offset,"remote VT Session ID: "); } static guint -fVtCloseRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fVtCloseRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - offset= fApplicationTypes (tvb,tree,offset,"remote VT Session ID: "); + offset= fApplicationTypes (tvb, pinfo, tree,offset,"remote VT Session ID: "); + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fVtDataRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fVtDataRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - offset= fApplicationTypes (tvb,tree,offset,"VT Session ID: "); - offset = fApplicationTypes (tvb, tree, offset, "VT New Data: "); - return fApplicationTypes (tvb,tree,offset,"VT Data Flag: ");; + offset= fApplicationTypes (tvb, pinfo, tree,offset,"VT Session ID: "); + offset = fApplicationTypes (tvb, pinfo, tree, offset, "VT New Data: "); + return fApplicationTypes (tvb, pinfo, tree,offset,"VT Data Flag: ");; } static guint @@ -3856,9 +7222,9 @@ fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + switch (fTagNo(tvb,offset)) { case 0: /* BOOLEAN */ offset = fBooleanTag (tvb, tree, offset, "all New Data Accepted: "); @@ -3869,6 +7235,7 @@ fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } @@ -3878,9 +7245,9 @@ fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + switch (fTagNo(tvb,offset)) { case 0: /* Unsigned32 */ offset = fUnsignedTag (tvb, tree, offset, "pseudo Random Number: "); @@ -3900,156 +7267,145 @@ fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fAuthenticateAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fAuthenticateAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fApplicationTypes (tvb, tree, offset, "modified Random Number: "); + return fApplicationTypes (tvb, pinfo, tree, offset, "modified Random Number: "); } static guint -fRequestKeyRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fRequestKeyRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - offset = fObjectIdentifier (tvb, tree, offset); /* Requesting Device Identifier */ + offset = fObjectIdentifier (tvb, pinfo, tree, offset); /* Requesting Device Identifier */ offset = fAddress (tvb, tree, offset); - offset = fObjectIdentifier (tvb, tree, offset); /* Remote Device Identifier */ + offset = fObjectIdentifier (tvb, pinfo, tree, offset); /* Remote Device Identifier */ return fAddress (tvb, tree, offset); } static guint -fRemoveListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fRemoveListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* Same as AddListElement request after service choice */ - return fAddListElementRequest(tvb, tree, offset); + return fAddListElementRequest(tvb, pinfo, tree, offset); } static guint -fReadPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fReadPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fBACnetObjectPropertyReference(tvb, tree, offset); + return fBACnetObjectPropertyReference(tvb, pinfo, tree, offset); } static guint -fReadPropertyAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fReadPropertyAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; - proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + /* set the optional global properties to indicate not-used */ + propertyArrayIndex = -1; + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); + offset += len; subtree = tree; continue; } switch (tag_no) { case 0: /* objectIdentifier */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 1: /* propertyIdentifier */ - offset = fPropertyIdentifier (tvb, subtree, offset); + offset = fPropertyIdentifier (tvb, pinfo, subtree, offset); break; case 2: /* propertyArrayIndex */ - offset = fSignedTag (tvb, subtree, offset, "property Array Index: "); + offset = fPropertyArrayIndex (tvb, subtree, offset); break; case 3: /* propertyValue */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); - break; - } - FAULT; + offset = fPropertyValue (tvb, pinfo, subtree, offset, tag_info); break; default: break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fWritePropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fWritePropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; - proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + /* set the optional global properties to indicate not-used */ + propertyArrayIndex = -1; + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); subtree = tree; - continue; + break; } - + switch (tag_no) { case 0: /* objectIdentifier */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 1: /* propertyIdentifier */ - offset = fPropertyIdentifier (tvb, subtree, offset); + offset = fPropertyIdentifier (tvb, pinfo, subtree, offset); break; case 2: /* propertyArrayIndex */ - offset = fSignedTag (tvb, subtree, offset, "property Array Index: "); + offset = fPropertyArrayIndex (tvb, subtree, offset); break; case 3: /* propertyValue */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); - break; - } - FAULT; + offset = fPropertyValue (tvb, pinfo, subtree, offset, tag_info); break; case 4: /* Priority (only used for write) */ - offset = fSignedTag (tvb, subtree, offset, "Priority: "); + offset = fUnsignedTag (tvb, subtree, offset, "Priority: "); break; default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset) +fWriteAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { - guint lastoffset = 0; + guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + /* maybe a listOfwriteAccessSpecifications if we spot a closing tag */ + if (tag_is_closing(tag_info)) { + offset += len; continue; } - + switch (tag_no) { case 0: /* objectIdentifier */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 1: /* listOfPropertyValues */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fBACnetPropertyValue (tvb, subtree, offset); + offset = fBACnetPropertyValue (tvb, pinfo, subtree, offset); break; } FAULT; @@ -4057,71 +7413,81 @@ fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fWritePropertyMultipleRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fWritePropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { if (offset >= tvb_reported_length(tvb)) return offset; - return fWriteAccessSpecification (tvb, tree, offset); + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ + return fWriteAccessSpecification (tvb, pinfo, tree, offset); } static guint -fPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 tagoffset, guint8 list) +fPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset, guint8 list) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + /* set the optional global properties to indicate not-used */ + propertyArrayIndex = -1; + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { /* closing Tag, but not for me */ return offset; + } else if (tag_is_opening(tag_info)) { /* opening Tag, but not for me */ + return offset; } switch (tag_no-tagoffset) { case 0: /* PropertyIdentifier */ - offset = fPropertyIdentifier (tvb, tree, offset); + offset = fPropertyIdentifier (tvb, pinfo, tree, offset); break; case 1: /* propertyArrayIndex */ - offset = fUnsignedTag (tvb, tree, offset, "property Array Index: "); + offset = fPropertyArrayIndex (tvb, tree, offset); if (list != 0) break; /* Continue decoding if this may be a list */ default: lastoffset = offset; /* Set loop end condition */ break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fBACnetPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 list) +fBACnetPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 list) { - return fPropertyReference(tvb, tree, offset, 0, list); + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ + return fPropertyReference(tvb, pinfo, tree, offset, 0, list); } static guint -fBACnetObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset) +fBACnetObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + switch (fTagNo(tvb,offset)) { case 0: /* ObjectIdentifier */ - offset = fObjectIdentifier (tvb, tree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 1: /* PropertyIdentifier and propertyArrayIndex */ - offset = fPropertyReference (tvb, tree, offset, 1, 0); + offset = fPropertyReference (tvb, pinfo, tree, offset, 1, 0); + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ default: lastoffset = offset; /* Set loop end condition */ break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } @@ -4136,7 +7502,7 @@ fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset) proto_tree* subtree = tree; proto_item* tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { @@ -4146,26 +7512,19 @@ fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset) } switch (tag_no) { case 0: /* ObjectIdentifier */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 1: /* PropertyIdentifier */ - offset = fPropertyIdentifier (tvb, subtree, offset); + offset = fPropertyIdentifier (tvb, pinfo, subtree, offset); break; case 2: /* propertyArrayIndex */ offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: "); break; case 3: /* Value */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); - break; - } - FAULT; + offset = fPropertyValue (tvb, subtree, offset, tag_info); break; case 4: /* Priority */ - offset = fSignedTag (tvb, subtree, offset, "Priority: "); + offset = fUnsignedTag (tvb, subtree, offset, "Priority: "); break; default: break; @@ -4175,105 +7534,98 @@ fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset) } #endif -#if 0 static guint -fDeviceObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset) +fPriorityArray (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { + char i = 1, ar[256]; guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; - - switch (fTagNo(tvb,offset)) { - case 0: /* ObjectIdentifier */ - offset = fBACnetObjectPropertyReference (tvb, tree, offset); - break; - case 3: /* deviceIdentifier */ - offset = fObjectIdentifier (tvb, tree, offset); - break; - default: - return offset; - } - } - return offset; -} -#endif - -static guint -fPriorityArray (tvbuff_t *tvb, proto_tree *tree, guint offset) -{ - char i, ar[256]; - - if (offset >= tvb_reported_length(tvb)) - return offset; - - for (i = 1; i <= 16; i++) { + if (propertyArrayIndex > 0) { + /* BACnetARRAY index 0 refers to the length + of the array, not the elements of the array. + BACnetARRAY index -1 is our internal flag that + the optional index was not used. + BACnetARRAY refers to this as all elements of the array. + If the optional index is specified for a BACnetARRAY, + then that specific array element is referenced. */ + i = propertyArrayIndex; + } + while (tvb_reported_length_remaining(tvb, offset)) { + /* exit loop if nothing happens inside */ + lastoffset = offset; g_snprintf (ar, sizeof(ar), "%s[%d]: ", val_to_split_str(87 , 512, BACnetPropertyIdentifier, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), - i); - /* DMR Replace with fAbstractNSyntax */ - offset = fApplicationTypes(tvb, tree, offset, ar); + i++); + /* DMR Should be fAbstractNSyntax, but that's where we came from! */ + offset = fApplicationTypes(tvb, pinfo, tree, offset, ar); + /* there are only 16 priority array elements */ + if (i > 16) { + break; + } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } + return offset; } -#if 0 static guint -fDeviceObjectReference (tvbuff_t *tvb, proto_tree *tree, guint offset) +fDeviceObjectReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + switch (fTagNo(tvb,offset)) { - case 0: /* deviceIdentifier */ - offset = fObjectIdentifier (tvb, tree, offset); + case 0: /* deviceIdentifier - OPTIONAL */ + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 1: /* ObjectIdentifier */ - offset = fObjectIdentifier (tvb, tree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } -#endif static guint -fSpecialEvent (tvbuff_t *tvb, proto_tree *subtree, guint offset) +fSpecialEvent (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; - guint lastoffset = 0; + guint lastoffset = 0, len; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + /* maybe a SEQUENCE of SpecialEvents if we spot a closing tag */ + if (tag_is_closing(tag_info)) { + offset += len; continue; } - + switch (tag_no) { case 0: /* calendaryEntry */ - if (tag_is_opening(tag_info)) - { + if (tag_is_opening(tag_info)) + { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fCalendaryEntry (tvb, subtree, offset); + offset = fCalendaryEntry (tvb, subtree, offset); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - } + } break; case 1: /* calendarReference */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 2: /* list of BACnetTimeValue */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fTimeValue (tvb, subtree, offset); + offset = fTimeValue (tvb, pinfo, subtree, offset); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); break; } @@ -4285,64 +7637,76 @@ fSpecialEvent (tvbuff_t *tvb, proto_tree *subtree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fSelectionCriteria (tvbuff_t *tvb, proto_tree *tree, guint offset) +fSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint lastoffset = 0, len; + guint8 tag_no, tag_info; + guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + /* maybe a listOfSelectionCriteria if we spot a closing tag */ + if (tag_is_closing(tag_info)) { + offset += len; + continue; + } + switch (fTagNo(tvb,offset)) { case 0: /* propertyIdentifier */ - offset = fPropertyIdentifier (tvb, tree, offset); + offset = fPropertyIdentifier (tvb, pinfo, tree, offset); break; case 1: /* propertyArrayIndex */ - offset = fUnsignedTag (tvb, tree, offset, "property Array Index: "); + offset = fPropertyArrayIndex (tvb, tree, offset); break; case 2: /* relationSpecifier */ - offset = fEnumeratedTag (tvb, tree, offset, + offset = fEnumeratedTag (tvb, tree, offset, "relation Specifier: ", BACnetRelationSpecifier); break; case 3: /* comparisonValue */ - offset = fAbstractSyntaxNType (tvb, tree, offset); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset); + offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset) +fObjectSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); - continue; + /* quit loop if we spot a closing tag */ + if (tag_is_closing(tag_info)) { + break; } - + switch (tag_no) { case 0: /* selectionLogic */ - offset = fEnumeratedTag (tvb, subtree, offset, + offset = fEnumeratedTag (tvb, subtree, offset, "selection Logic: ", BACnetSelectionLogic); break; case 1: /* listOfSelectionCriteria */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fSelectionCriteria (tvb, subtree, offset); + offset = fSelectionCriteria (tvb, pinfo, subtree, offset); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); break; } FAULT; @@ -4350,107 +7714,108 @@ fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fReadPropertyConditionalRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset) +fReadPropertyConditionalRequest(tvbuff_t *tvb, packet_info* pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { + + if (tag_is_opening(tag_info) && tag_no < 2) { offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - continue; - } - - switch (tag_no) { - case 0: /* objectSelectionCriteria */ - offset = fObjectSelectionCriteria (tvb, subtree, offset); - break; - case 1: /* listOfPropertyReferences */ - if (tag_is_opening(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fBACnetPropertyReference (tvb, subtree, offset, 1); + switch (tag_no) { + case 0: /* objectSelectionCriteria */ + offset = fObjectSelectionCriteria (tvb, pinfo, subtree, offset); break; + case 1: /* listOfPropertyReferences */ + offset = fBACnetPropertyReference (tvb, pinfo, subtree, offset, 1); + break; + default: + return offset; } - FAULT; - break; - default: - return offset; + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fReadAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset) +fReadAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; + proto_item *tt; + proto_tree *subtree = tree; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, - &tag_info, &lvt); - continue; - } - switch (tag_no) { case 0: /* objectIdentifier */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); break; case 1: /* listOfPropertyReferences */ if (tag_is_opening(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fBACnetPropertyReference (tvb, subtree, offset, 1); - break; + tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfPropertyReferences"); + subtree = proto_item_add_subtree(tt, ett_bacapp_value); + offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fBACnetPropertyReference (tvb, pinfo, subtree, offset, 1); + } else if (tag_is_closing(tag_info)) { + offset += fTagHeaderTree (tvb, subtree, offset, + &tag_no, &tag_info, &lvt); + subtree = tree; + } else { + /* error condition: let caller handle */ + return offset; } - FAULT; break; default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset) +fReadAccessResult (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint lastoffset = 0, len; guint8 tag_no; guint8 tag_info; guint32 lvt; proto_tree *subtree = tree; proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); - if (tag_no == 4 || tag_no == 5) subtree = tree; /* Value and error have extra subtree */ + len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + /* maybe a listOfReadAccessResults if we spot a closing tag here */ + if (tag_is_closing(tag_info)) { + offset += len; + if ((tag_no == 4 || tag_no == 5) && (subtree != tree)) subtree = subtree->parent; /* Value and error have extra subtree */ continue; } - + switch (tag_no) { case 0: /* objectSpecifier */ - offset = fObjectIdentifier (tvb, subtree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); break; case 1: /* list of Results */ if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfResults"); + tt = proto_tree_add_text(tree, tvb, offset, 1, "listOfResults"); subtree = proto_item_add_subtree(tt, ett_bacapp_value); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); break; @@ -4458,15 +7823,15 @@ fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset) FAULT; break; case 2: /* propertyIdentifier */ - offset = fPropertyValue(tvb, subtree, offset, 2); + offset = fPropertyIdentifierValue(tvb, pinfo, subtree, offset, 2); break; case 5: /* propertyAccessError */ if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyAccessError"); + tt = proto_tree_add_text(tree, tvb, offset, 1, "propertyAccessError"); subtree = proto_item_add_subtree(tt, ett_bacapp_value); offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); /* Error Code follows */ - offset = fError(tvb, subtree, offset); + offset = fError(tvb, pinfo, subtree, offset); break; } FAULT; @@ -4474,219 +7839,152 @@ fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fReadPropertyConditionalAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fReadPropertyConditionalAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* listOfReadAccessResults */ - return fReadAccessResult (tvb, tree, offset); + return fReadAccessResult (tvb, pinfo, tree, offset); } static guint -fObjectSpecifier (tvbuff_t *tvb, proto_tree *tree, guint offset) -{ - guint lastoffset = 0; - - while ((tvb_length_remaining(tvb, offset) > 0)&&(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) +fCreateObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; - while ((tvb_length_remaining(tvb, offset) > 0) && (offset > lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); - continue; - } - - switch (tag_no) { - case 0: /* objectSpecifier */ - offset = fObjectSpecifier (tvb, subtree, offset); - break; - case 1: /* propertyValue */ - if (tag_is_opening(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fBACnetPropertyValue (tvb, subtree, offset); + + if (tag_no < 2) + { + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + switch (tag_no) { + case 0: /* objectSpecifier */ + switch (fTagNo(tvb, offset)) { /* choice of objectType or objectIdentifier */ + case 0: /* objectType */ + offset = fEnumeratedTagSplit (tvb, subtree, offset, "Object Type: ", BACnetObjectType, 128); + break; + case 1: /* objectIdentifier */ + offset = fObjectIdentifier (tvb, pinfo, subtree, offset); + break; + default: + break; + } + break; + case 1: /* propertyValue */ + if (tag_is_opening(tag_info)) { + offset = fBACnetPropertyValue (tvb, pinfo, subtree, offset); + break; + } + FAULT; + break; + default: break; } - FAULT; - break; - default: - return offset; + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fCreateObjectAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fObjectIdentifier (tvb, tree, offset); + return fObjectIdentifier (tvb, pinfo, tree, offset); } static guint -fReadRangeRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fReadRangeRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; + offset = fBACnetObjectPropertyReference(tvb, pinfo, subtree, offset); + + if (tvb_reported_length_remaining(tvb, offset) > 0) { + /* optional range choice */ fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); - subtree = tree; - continue; - } - - switch (tag_no) { - case 0: /* objectSpecifier */ - offset = fObjectIdentifier (tvb, subtree, offset); - break; - case 1: /* propertyIdentifier */ - offset = fPropertyIdentifier (tvb, subtree, offset); - break; - case 2: /* propertyArrayIndex Optional */ - offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: "); - break; - case 3: /* range byPosition */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "range byPosition"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fApplicationTypes (tvb, subtree, offset, "reference Index: "); - offset = fApplicationTypes (tvb, subtree, offset, "reference Count: "); + if (tag_is_opening(tag_info)) { + tt = proto_tree_add_text(subtree, tvb, offset, 1, "%s", val_to_str(tag_no, BACnetReadRangeOptions, "unknown range option")); + subtree = proto_item_add_subtree(tt, ett_bacapp_value); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + switch (tag_no) { + case 3: /* range byPosition */ + case 6: /* range bySequenceNumber, 2004 spec */ + offset = fApplicationTypes (tvb, pinfo, subtree, offset, "reference Index: "); + offset = fApplicationTypes (tvb, pinfo, subtree, offset, "reference Count: "); break; - } - FAULT; - break; - case 4: /* range byTime */ - case 7: /* 2004 spec */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "range byTime"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + case 4: /* range byTime - deprecated in 2004 */ + case 7: /* 2004 spec */ offset = fDateTime(tvb, subtree, offset, "reference Date/Time: "); - offset = fApplicationTypes (tvb, subtree, offset, "reference Count: "); + offset = fApplicationTypes (tvb, pinfo, subtree, offset, "reference Count: "); break; - } - FAULT; - break; - case 5: /* range timeRange */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "range timeRange"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fApplicationTypes (tvb, subtree, offset, "beginning Time: "); - offset = fApplicationTypes (tvb, subtree, offset, "ending Time: "); + case 5: /* range timeRange - deprecated in 2004 */ + offset = fDateTime(tvb, subtree, offset, "beginning Time: "); + offset = fDateTime(tvb, subtree, offset, "ending Time: "); break; - } - FAULT; - break; - case 6: /* range bySequenceNumber, 2004 spec */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "range bySequenceNumber"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fApplicationTypes (tvb, subtree, offset, "referenceIndex: "); - offset = fApplicationTypes (tvb, subtree, offset, "reference Count: "); + default: break; - } - FAULT; - break; - default: - return offset; + } + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); } } return offset; } static guint -fReadRangeAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fReadRangeAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - subtree = tree; - continue; - } - - switch (tag_no) { - case 0: /* objectSpecifier */ - offset = fObjectIdentifier (tvb, subtree, offset); - break; - case 1: /* propertyIdentifier */ - offset = fPropertyIdentifier (tvb, subtree, offset); - break; - case 2: /* propertyArrayIndex Optional */ - offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: "); - break; - case 3: /* resultFlags */ - offset = fEnumeratedTag (tvb, tree, offset, - "result Flags: ", BACnetResultFlags); - break; - case 4: /* itemCount */ - offset = fUnsignedTag (tvb, subtree, offset, "item Count: "); - break; - case 5: /* itemData */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "itemData"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fAbstractSyntaxNType (tvb, subtree, offset); - break; - } - FAULT; - break; - case 6: /* firstSequenceNumber */ - offset = fUnsignedTag (tvb, subtree, offset, "first Sequence Number: "); - break; - default: - return offset; - } + /* set the optional global properties to indicate not-used */ + propertyArrayIndex = -1; + /* objectIdentifier, propertyIdentifier, and + OPTIONAL propertyArrayIndex */ + offset = fBACnetObjectPropertyReference(tvb, pinfo, subtree, offset); + /* resultFlags => BACnetResultFlags ::= BIT STRING */ + offset = fBitStringTagVS (tvb, tree, offset, + "resultFlags: ", + BACnetResultFlags); + /* itemCount */ + offset = fUnsignedTag (tvb, subtree, offset, "item Count: "); + /* itemData */ + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_is_opening(tag_info)) { + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ + tt = proto_tree_add_text(subtree, tvb, offset, 1, "itemData"); + subtree = proto_item_add_subtree(tt, ett_bacapp_value); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); } + /* firstSequenceNumber - OPTIONAL */ + if (tvb_reported_length_remaining(tvb, offset) > 0) { + offset = fUnsignedTag (tvb, subtree, offset, "first Sequence Number: "); + } + return offset; } -static guint fAccessMethod(tvbuff_t *tvb, proto_tree *tree, guint offset) +static guint +fAccessMethod(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { + guint lastoffset = 0; guint32 lvt; guint8 tag_no, tag_info; proto_item* tt; @@ -4694,104 +7992,65 @@ static guint fAccessMethod(tvbuff_t *tvb, proto_tree *tree, guint offset) fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - switch (tag_no) { - case 0: /* streamAccess */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(tree, tvb, offset, 1, "stream Access"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fApplicationTypes (tvb, subtree, offset, "File Start Position: "); - offset = fApplicationTypes (tvb, subtree, offset, "file Data: "); - } - if (bacapp_flags & 0x04) { /* More Flag is set */ - break; - } - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - } - break; - case 1: /* recordAccess */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(tree, tvb, offset, 1, "record Access"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fApplicationTypes (tvb, subtree, offset, "File Start Record: "); - offset = fApplicationTypes (tvb, subtree, offset, "Record Count: "); - offset = fApplicationTypes (tvb, subtree, offset, "Data: "); - } - if (bacapp_flags & 0x04) { /* More Flag is set */ - break; + if (tag_is_opening(tag_info)) + { + tt = proto_tree_add_text(tree, tvb, offset, 1, "%s", val_to_str(tag_no, BACnetFileAccessOption, "invalid access method")); + subtree = proto_item_add_subtree(tt, ett_bacapp_value); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fApplicationTypes (tvb, pinfo, subtree, offset, val_to_str(tag_no, BACnetFileStartOption, "invalid option")); + offset = fApplicationTypes (tvb, pinfo, subtree, offset, val_to_str(tag_no, BACnetFileWriteInfo, "unknown option")); + + if (tag_no == 1) + { + while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) + { /* exit loop if nothing happens inside */ + lastoffset = offset; + offset = fApplicationTypes (tvb, pinfo, subtree, offset, "Record Data: "); + } } - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + + if ((bacapp_flags & BACAPP_MORE_SEGMENTS) == 0) + { + /* More Flag is not set, so we can look for closing tag in this segment */ + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + if (tag_is_closing(tag_info)) { + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + } } - break; - default: - break; } - return offset; } static guint -fAtomicReadFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fAtomicReadFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; - proto_item *tt; - - offset = fObjectIdentifier (tvb, tree, offset); - - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - if (tag_is_closing(tag_info)) { - offset += fTagHeaderTree (tvb, subtree, offset, - &tag_no, &tag_info, &lvt); - subtree = tree; - continue; - } - - switch (tag_no) { - case 0: /* streamAccess */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "stream Access"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fSignedTag (tvb, subtree, offset, "File Start Position: "); - offset = fUnsignedTag (tvb, subtree, offset, "requested Octet Count: "); - break; - } - FAULT; - break; - case 1: /* recordAccess */ - if (tag_is_opening(tag_info)) { - tt = proto_tree_add_text(subtree, tvb, offset, 1, "record Access"); - subtree = proto_item_add_subtree(tt, ett_bacapp_value); - offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); - offset = fSignedTag (tvb, subtree, offset, "File Start Record: "); - offset = fUnsignedTag (tvb, subtree, offset, "requested Record Count: "); - break; - } - FAULT; - break; - default: - return offset; - } + proto_item *tt; + + offset = fObjectIdentifier (tvb, pinfo, tree, offset); + + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + + if (tag_is_opening(tag_info)) + { + tt = proto_tree_add_text(subtree, tvb, offset, 1, "%s", val_to_str(tag_no, BACnetFileAccessOption, "unknown access method")); + subtree = proto_item_add_subtree(tt, ett_bacapp_value); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fSignedTag (tvb, subtree, offset, val_to_str(tag_no, BACnetFileStartOption, "unknown option")); + offset = fUnsignedTag (tvb, subtree, offset, val_to_str(tag_no, BACnetFileRequestCount, "unknown option")); + offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); } return offset; } static guint -fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset) +fAtomicWriteFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - offset = fObjectIdentifier (tvb, tree, offset); /* file Identifier */ - offset = fAccessMethod(tvb, tree, offset); + offset = fObjectIdentifier (tvb, pinfo, tree, offset); /* file Identifier */ + offset = fAccessMethod(tvb, pinfo, tree, offset); return offset; } @@ -4799,196 +8058,183 @@ fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint 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; + guint tag_no = fTagNo(tvb, offset); + return fSignedTag (tvb, tree, offset, val_to_str(tag_no, BACnetFileStartOption, "unknown option")); } static guint -fAtomicReadFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fAtomicReadFileAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint8 tag_no, tag_info; - guint32 lvt; - proto_tree *subtree = tree; - - fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); - offset = fApplicationTypes (tvb, subtree, offset, "End Of File: "); - offset = fAccessMethod(tvb, tree, offset); + offset = fApplicationTypes (tvb, pinfo, tree, offset, "End Of File: "); + offset = fAccessMethod(tvb,pinfo, tree, offset); - return offset; + return offset; } static guint -fReadPropertyMultipleRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset) +fReadPropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { - return fReadAccessSpecification (tvb,subtree,offset); + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ + return fReadAccessSpecification (tvb,pinfo,subtree,offset); } static guint -fReadPropertyMultipleAck (tvbuff_t *tvb, proto_tree *tree, guint offset) +fReadPropertyMultipleAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - return fReadAccessResult (tvb,tree,offset); + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ + return fReadAccessResult (tvb,pinfo,tree,offset); } static guint -fConfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice) +fConfirmedServiceRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice) { - if (tvb_length_remaining(tvb,offset) <= 0) + if (tvb_reported_length_remaining(tvb,offset) <= 0) return offset; switch (service_choice) { case 0: /* acknowledgeAlarm */ - offset = fAcknowledgeAlarmRequest (tvb, tree, offset); + offset = fAcknowledgeAlarmRequest (tvb, pinfo, tree, offset); break; case 1: /* confirmedCOVNotification */ - offset = fConfirmedCOVNotificationRequest (tvb, tree, offset); + offset = fConfirmedCOVNotificationRequest (tvb, pinfo, tree, offset); break; case 2: /* confirmedEventNotification */ - offset = fConfirmedEventNotificationRequest (tvb, tree, offset); + offset = fConfirmedEventNotificationRequest (tvb, pinfo, tree, offset); break; case 3: /* confirmedGetAlarmSummary conveys no parameters */ break; case 4: /* getEnrollmentSummaryRequest */ - offset = fGetEnrollmentSummaryRequest (tvb, tree, offset); + offset = fGetEnrollmentSummaryRequest (tvb, pinfo, tree, offset); break; case 5: /* subscribeCOVRequest */ - offset = fSubscribeCOVRequest(tvb, tree, offset); + offset = fSubscribeCOVRequest(tvb, pinfo, tree, offset); break; case 6: /* atomicReadFile-Request */ - offset = fAtomicReadFileRequest(tvb, tree, offset); + offset = fAtomicReadFileRequest(tvb, pinfo, tree, offset); break; case 7: /* atomicWriteFile-Request */ - offset = fAtomicWriteFileRequest(tvb, tree, offset); + offset = fAtomicWriteFileRequest(tvb, pinfo, tree, offset); break; case 8: /* AddListElement-Request */ - offset = fAddListElementRequest(tvb, tree, offset); + offset = fAddListElementRequest(tvb, pinfo, tree, offset); break; case 9: /* removeListElement-Request */ - offset = fRemoveListElementRequest(tvb, tree, offset); + offset = fRemoveListElementRequest(tvb, pinfo, tree, offset); break; case 10: /* createObjectRequest */ - offset = fCreateObjectRequest(tvb, tree, offset); + offset = fCreateObjectRequest(tvb, pinfo, tree, offset); break; case 11: /* deleteObject */ - offset = fDeleteObjectRequest(tvb, tree, offset); + offset = fDeleteObjectRequest(tvb, pinfo, tree, offset); break; case 12: - offset = fReadPropertyRequest(tvb, tree, offset); + offset = fReadPropertyRequest(tvb, pinfo, tree, offset); break; case 13: - offset = fReadPropertyConditionalRequest(tvb, tree, offset); + offset = fReadPropertyConditionalRequest(tvb, pinfo, tree, offset); break; case 14: - offset = fReadPropertyMultipleRequest(tvb, tree, offset); + offset = fReadPropertyMultipleRequest(tvb, pinfo, tree, offset); break; case 15: - offset = fWritePropertyRequest(tvb, tree, offset); + offset = fWritePropertyRequest(tvb, pinfo, tree, offset); break; case 16: - offset = fWritePropertyMultipleRequest(tvb, tree, offset); + offset = fWritePropertyMultipleRequest(tvb, pinfo, tree, offset); break; case 17: offset = fDeviceCommunicationControlRequest(tvb, tree, offset); break; case 18: - offset = fConfirmedPrivateTransferRequest(tvb, tree, offset); + offset = fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset); break; case 19: - offset = fConfirmedTextMessageRequest(tvb, tree, offset); + offset = fConfirmedTextMessageRequest(tvb, pinfo, tree, offset); break; case 20: offset = fReinitializeDeviceRequest(tvb, tree, offset); break; case 21: - offset = fVtOpenRequest(tvb, tree, offset); + offset = fVtOpenRequest(tvb, pinfo, tree, offset); break; case 22: - offset = fVtCloseRequest (tvb, tree, offset); + offset = fVtCloseRequest (tvb, pinfo, tree, offset); break; case 23: - offset = fVtDataRequest (tvb, tree, offset); + offset = fVtDataRequest (tvb, pinfo, tree, offset); break; case 24: offset = fAuthenticateRequest (tvb, tree, offset); break; case 25: - offset = fRequestKeyRequest (tvb, tree, offset); + offset = fRequestKeyRequest (tvb, pinfo, tree, offset); break; case 26: - offset = fReadRangeRequest (tvb, tree, offset); + offset = fReadRangeRequest (tvb, pinfo, tree, offset); break; case 27: - offset = fLifeSafetyOperationRequest(tvb, tree, offset, NULL); + offset = fLifeSafetyOperationRequest(tvb, pinfo, tree, offset, NULL); break; case 28: - offset = fSubscribeCOVPropertyRequest(tvb, tree, offset); + offset = fSubscribeCOVPropertyRequest(tvb, pinfo, tree, offset); break; case 29: - offset = fGetEventInformationRequest (tvb, tree, offset); + offset = fGetEventInformationRequest (tvb, pinfo, tree, offset); break; default: return offset; - break; } return offset; } static guint -fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice) +fConfirmedServiceAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice) { - if (tvb_length_remaining(tvb,offset) <= 0) + if (tvb_reported_length_remaining(tvb,offset) <= 0) return offset; switch (service_choice) { case 3: /* confirmedEventNotificationAck */ - offset = fGetAlarmSummaryAck (tvb, tree, offset); + offset = fGetAlarmSummaryAck (tvb, pinfo, tree, offset); break; case 4: /* getEnrollmentSummaryAck */ - offset = fGetEnrollmentSummaryAck (tvb, tree, offset); + offset = fGetEnrollmentSummaryAck (tvb, pinfo, tree, offset); break; case 6: /* atomicReadFile */ - offset = fAtomicReadFileAck (tvb, tree, offset); + offset = fAtomicReadFileAck (tvb, pinfo, tree, offset); break; case 7: /* atomicReadFileAck */ offset = fAtomicWriteFileAck (tvb, tree, offset); break; case 10: /* createObject */ - offset = fCreateObjectAck (tvb, tree, offset); + offset = fCreateObjectAck (tvb, pinfo, tree, offset); break; case 12: - offset = fReadPropertyAck (tvb, tree, offset); + offset = fReadPropertyAck (tvb, pinfo, tree, offset); break; case 13: - offset = fReadPropertyConditionalAck (tvb, tree, offset); + offset = fReadPropertyConditionalAck (tvb, pinfo, tree, offset); break; case 14: - offset = fReadPropertyMultipleAck (tvb, tree, offset); + offset = fReadPropertyMultipleAck (tvb, pinfo, tree, offset); break; case 18: - offset = fConfirmedPrivateTransferAck(tvb, tree, offset); + offset = fConfirmedPrivateTransferAck(tvb, pinfo, tree, offset); break; case 21: - offset = fVtOpenAck (tvb, tree, offset); + offset = fVtOpenAck (tvb, pinfo, tree, offset); break; case 23: offset = fVtDataAck (tvb, tree, offset); break; case 24: - offset = fAuthenticateAck (tvb, tree, offset); + offset = fAuthenticateAck (tvb, pinfo, tree, offset); break; case 26: - offset = fReadRangeAck (tvb, tree, offset); + offset = fReadRangeAck (tvb, pinfo, tree, offset); break; case 29: - offset = fGetEventInformationACK (tvb, tree, offset); + offset = fGetEventInformationACK (tvb, pinfo, tree, offset); break; default: return offset; @@ -4997,33 +8243,33 @@ fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint servic } static guint -fIAmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fIAmRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* BACnetObjectIdentifier */ - offset = fApplicationTypes (tvb, tree, offset, "BACnet Object Identifier: "); + offset = fApplicationTypes (tvb, pinfo, tree, offset, "BACnet Object Identifier: "); /* MaxAPDULengthAccepted */ - offset = fApplicationTypes (tvb, tree, offset, "Maximum ADPU Length Accepted: "); + offset = fApplicationTypes (tvb, pinfo, tree, offset, "Maximum ADPU Length Accepted: "); /* segmentationSupported */ - offset = fApplicationTypesEnumerated (tvb, tree, offset, + offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, "Segmentation Supported: ", BACnetSegmentation); /* vendor ID */ - return fUnsignedTag (tvb, tree, offset, "Vendor ID: "); + return fVendorIdentifier (tvb, pinfo, tree, offset); } static guint -fIHaveRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) +fIHaveRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* BACnetDeviceIdentifier */ - offset = fApplicationTypes (tvb, tree, offset, "Device Identifier: "); + offset = fApplicationTypes (tvb, pinfo, tree, offset, "Device Identifier: "); /* BACnetObjectIdentifier */ - offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: "); + offset = fApplicationTypes (tvb, pinfo, tree, offset, "Object Identifier: "); /* ObjectName */ - return fApplicationTypes (tvb, tree, offset, "Object Name: "); + return fApplicationTypes (tvb, pinfo, tree, offset, "Object Name: "); } @@ -5032,7 +8278,7 @@ fWhoIsRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* DeviceInstanceRangeLowLimit Optional */ @@ -5043,42 +8289,42 @@ fWhoIsRequest (tvbuff_t *tvb, proto_tree *tree, guint offset) break; default: return offset; - break; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fUnconfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice) +fUnconfirmedServiceRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice) { - if (tvb_length_remaining(tvb,offset) <= 0) + if (tvb_reported_length_remaining(tvb,offset) <= 0) return offset; - + switch (service_choice) { case 0: /* I-Am-Request */ - offset = fIAmRequest (tvb, tree, offset); + offset = fIAmRequest (tvb, pinfo, tree, offset); break; case 1: /* i-Have Request */ - offset = fIHaveRequest (tvb, tree, offset); + offset = fIHaveRequest (tvb, pinfo, tree, offset); break; case 2: /* unconfirmedCOVNotification */ - offset = fUnconfirmedCOVNotificationRequest (tvb, tree, offset); + offset = fUnconfirmedCOVNotificationRequest (tvb, pinfo, tree, offset); break; case 3: /* unconfirmedEventNotification */ - offset = fUnconfirmedEventNotificationRequest (tvb, tree, offset); + offset = fUnconfirmedEventNotificationRequest (tvb, pinfo, tree, offset); break; case 4: /* unconfirmedPrivateTransfer */ - offset = fUnconfirmedPrivateTransferRequest(tvb, tree, offset); + offset = fUnconfirmedPrivateTransferRequest(tvb, pinfo, tree, offset); break; case 5: /* unconfirmedTextMessage */ - offset = fUnconfirmedTextMessageRequest(tvb, tree, offset); + offset = fUnconfirmedTextMessageRequest(tvb, pinfo, tree, offset); break; case 6: /* timeSynchronization */ offset = fTimeSynchronizationRequest (tvb, tree, offset); break; case 7: /* who-Has */ - offset = fWhoHas (tvb, tree, offset); + offset = fWhoHas (tvb, pinfo, tree, offset); break; case 8: /* who-Is */ offset = fWhoIsRequest (tvb, tree, offset); @@ -5093,7 +8339,7 @@ fUnconfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint } static guint -fStartConfirmed(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset, guint8 ack, +fStartConfirmed(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset, guint8 ack, gint *svc, proto_item **tt) { proto_item *tc; @@ -5113,12 +8359,12 @@ fStartConfirmed(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset, guint8 ack if (bacapp_flags & 0x08) *svc = (gint) tvb_get_guint8(tvb, offset+extra+2); - proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE); + proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE); tc = proto_tree_add_item(bacapp_tree, hf_bacapp_pduflags, tvb, offset, 1, TRUE); bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp_control); - 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_SEG, tvb, offset, 1, TRUE); + proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, offset, 1, TRUE); if (ack == 0) /* The following are for ConfirmedRequest, not Complex ack */ { proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, offset++, 1, TRUE); @@ -5127,58 +8373,57 @@ fStartConfirmed(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset, guint8 ack proto_tree_add_item(bacapp_tree, 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); - } - *tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, 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, hf_bacapp_sequence_number, tvb, + offset++, 1, TRUE); + proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb, + offset++, 1, TRUE); + } + *tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb, + offset++, 1, TRUE); return offset; } static guint -fConfirmedRequestPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset) +fContinueConfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset, gint svc) +{ /* BACnet-Confirmed-Request */ + /* ASHRAE 135-2001 20.1.2 */ + + return fConfirmedServiceRequest (tvb, pinfo, bacapp_tree, offset, svc); +} + +static guint +fConfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset) { /* BACnet-Confirmed-Request */ /* ASHRAE 135-2001 20.1.2 */ gint svc; proto_item *tt = 0; - offset = fStartConfirmed(tvb, bacapp_tree, offset, 0, &svc, &tt); - if (bacapp_seq > 0) /* Can't handle continuation segments, so just treat as data */ - { - proto_tree_add_text(bacapp_tree, tvb, offset, 0, "(continuation)"); - return offset; - } - else - { - /* Service Request follows... Variable Encoding 20.2ff */ - return fConfirmedServiceRequest (tvb, bacapp_tree, offset, svc); - } + offset = fStartConfirmed(tvb, pinfo, bacapp_tree, offset, 0, &svc, &tt); + return fContinueConfirmedRequestPDU(tvb, pinfo, bacapp_tree, offset, svc); } static guint -fUnconfirmedRequestPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset) +fUnconfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset) { /* BACnet-Unconfirmed-Request-PDU */ /* ASHRAE 135-2001 20.1.3 */ gint tmp; - proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE); + proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE); - tmp = tvb_get_guint8(tvb, offset); - proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb, - offset++, 1, TRUE); - /* Service Request follows... Variable Encoding 20.2ff */ - return fUnconfirmedServiceRequest (tvb, bacapp_tree, offset, tmp); + tmp = tvb_get_guint8(tvb, offset); + proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb, + offset++, 1, TRUE); + /* Service Request follows... Variable Encoding 20.2ff */ + return fUnconfirmedServiceRequest (tvb, pinfo, bacapp_tree, offset, tmp); } static guint -fSimpleAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset) +fSimpleAckPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset) { /* BACnet-Simple-Ack-PDU */ /* ASHRAE 135-2001 20.1.4 */ @@ -5186,125 +8431,125 @@ fSimpleAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset) 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); + 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, proto_tree *bacapp_tree, guint offset) +fContinueComplexAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset, gint svc) +{ /* BACnet-Complex-Ack-PDU */ + /* ASHRAE 135-2001 20.1.5 */ + + /* Service ACK follows... */ + return fConfirmedServiceAck (tvb, pinfo, bacapp_tree, offset, svc); +} + +static guint +fComplexAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset) { /* BACnet-Complex-Ack-PDU */ /* ASHRAE 135-2001 20.1.5 */ gint svc; proto_item *tt = 0; - offset = fStartConfirmed(tvb, bacapp_tree, offset, 1, &svc, &tt); - - if (bacapp_seq > 0) /* Can't handle continuation segments, so just treat as data */ - { - proto_tree_add_text(bacapp_tree, tvb, offset, 0, "(continuation)"); - return offset; - } - else - { - /* Service ACK follows... */ - return fConfirmedServiceAck (tvb, bacapp_tree, offset, svc); - } + offset = fStartConfirmed(tvb, pinfo, bacapp_tree, offset, 1, &svc, &tt); + return fContinueComplexAckPDU(tvb, pinfo, bacapp_tree, offset, svc); } - static guint -fSegmentAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset) +fSegmentAckPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset) { /* BACnet-SegmentAck-PDU */ /* ASHRAE 135-2001 20.1.6 */ proto_item *tc; proto_tree *bacapp_tree_control; - 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); + 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); return offset; } -static guint fContextTaggedError(tvbuff_t *tvb, proto_tree *tree, guint offset) +static guint +fContextTaggedError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint8 tag_info = 0; - guint8 parsed_tag = 0; - guint32 lvt = 0; - offset += fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt); - offset = fError(tvb, tree, offset); - return offset + fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt); + guint8 tag_info = 0; + guint8 parsed_tag = 0; + guint32 lvt = 0; + offset += fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt); + offset = fError(tvb, pinfo, tree, offset); + return offset + fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt); } static guint -fConfirmedPrivateTransferError(tvbuff_t *tvb, proto_tree *tree, guint offset) +fConfirmedPrivateTransferError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; + guint8 tag_no = 0, tag_info = 0; + guint32 lvt = 0; + proto_tree *subtree = tree; + proto_item *tt; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { + /* exit loop if nothing happens inside */ lastoffset = offset; - switch (fTagNo(tvb, offset)) { + fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt); + switch (tag_no) { case 0: /* errorType */ - offset = fContextTaggedError(tvb,tree,offset); + offset = fContextTaggedError(tvb, pinfo, subtree, offset); break; case 1: /* vendorID */ - offset = fUnsignedTag (tvb,tree,offset,"vendor ID: "); + offset = fVendorIdentifier (tvb, pinfo, subtree, offset); 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 ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; - switch (fTagNo(tvb, offset)) { - case 0: /* errorType */ - offset = fContextTaggedError(tvb,tree,offset); + offset = fUnsignedTag (tvb, subtree, offset, "service Number: "); break; - case 1: /* firstFailedElementNumber */ - offset = fUnsignedTag (tvb,tree,offset,"first failed element number: "); + case 3: /* errorParameters */ + if (tag_is_opening(tag_info)) { + tt = proto_tree_add_text(subtree, tvb, offset, 1, + "error Parameters"); + subtree = proto_item_add_subtree(tt, ett_bacapp_value); + propertyIdentifier = -1; + offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); + offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset); + } else if (tag_is_closing(tag_info)) { + offset += fTagHeaderTree (tvb, subtree, offset, + &tag_no, &tag_info, &lvt); + subtree = tree; + } else { + /* error condition: let caller handle */ + return offset; + } break; default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset) +fCreateObjectError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* errorType */ - offset = fContextTaggedError(tvb,tree,offset); + offset = fContextTaggedError(tvb, pinfo, tree, offset); break; case 1: /* firstFailedElementNumber */ offset = fUnsignedTag (tvb,tree,offset,"first failed element number: "); @@ -5312,312 +8557,466 @@ fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset) default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } -#if 0 static guint -fVTSession(tvbuff_t *tvb, proto_tree *tree, guint offset) +fChangeListError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - if (tvb_length_remaining(tvb, offset) > 0) { /* don't loop */ - offset = fUnsignedTag (tvb,tree,offset, "local-VTSessionID: "); - offset = fUnsignedTag (tvb,tree,offset, "remote-VTSessionID: "); - offset = fAddress (tvb,tree,offset); - } - return offset; + /* Identical to CreateObjectError */ + return fCreateObjectError(tvb, pinfo, tree, offset); } -#endif static guint -fVTCloseError(tvbuff_t *tvb, proto_tree *tree, guint offset) +fVTCloseError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - guint lastoffset = 0; + guint8 tag_no = 0, tag_info = 0; + guint32 lvt = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ - lastoffset = offset; - switch (fTagNo(tvb, offset)) { - case 0: /* errorType */ - offset = fContextTaggedError(tvb,tree,offset); - break; - case 1: /* listOfVTSessionIdentifiers */ - offset = fUnsignedTag (tvb,tree,offset,"VT SessionID: "); - break; - default: - return offset; + if (fTagNo(tvb, offset) == 0) + { + /* errorType */ + offset = fContextTaggedError(tvb, pinfo, tree,offset); + if (fTagNo(tvb, offset) == 1) + { + /* listOfVTSessionIdentifiers [OPTIONAL] */ + offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset = fVtCloseRequest (tvb, pinfo, tree, offset); + offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); } } + /* should report bad packet if initial tag wasn't 0 */ return offset; } static guint -fWritePropertyMultipleError(tvbuff_t *tvb, proto_tree *tree, guint offset) +fWritePropertyMultipleError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; + guint8 tag_no = 0, tag_info = 0; + guint32 lvt = 0; - while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ + col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */ + while (tvb_reported_length_remaining(tvb, offset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* errorType */ - offset = fContextTaggedError(tvb,tree,offset); + offset = fContextTaggedError(tvb, pinfo, tree, offset); break; case 1: /* firstFailedWriteAttempt */ - offset = fUnsignedTag (tvb,tree,offset,"first failed write attempt: "); + offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); + offset = fBACnetObjectPropertyReference(tvb, pinfo, tree, offset); + offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } + if (offset == lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint -fError (tvbuff_t *tvb, proto_tree *tree, guint offset) +fError (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { - offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, - "error Class: ", BACnetErrorClass, 64); - return fApplicationTypesEnumeratedSplit (tvb, tree, offset, - "error Code: ", BACnetErrorCode, 256); + offset = fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset, + "error Class: ", BACnetErrorClass, 64); + return fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset, + "error Code: ", BACnetErrorCode, 256); } static guint -fBACnetError (tvbuff_t *tvb, proto_tree *tree, guint offset, guint service) +fBACnetError (tvbuff_t *tvb, packet_info *pinfo, 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; + switch (service) { + case 8: /* no break here !!!! */ + case 9: + offset = fChangeListError (tvb, pinfo, tree, offset); + break; + case 10: + offset = fCreateObjectError (tvb, pinfo, tree, offset); + break; + case 16: + offset = fWritePropertyMultipleError (tvb, pinfo, tree, offset); + break; + case 18: + offset = fConfirmedPrivateTransferError (tvb,pinfo,tree,offset); + break; + case 22: + offset = fVTCloseError (tvb, pinfo, tree, offset); + break; + default: + return fError (tvb, pinfo, tree, offset); + } + return offset; } static guint -fErrorPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset) +fErrorPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset) { /* BACnet-Error-PDU */ /* ASHRAE 135-2001 20.1.7 */ proto_item *tc, *tt; proto_tree *bacapp_tree_control; - guint8 tmp; + guint8 tmp; - tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE); - bacapp_tree_control = proto_item_add_subtree(tc, 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... */ - return fBACnetError (tvb, bacapp_tree, offset, tmp); + 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... */ + return fBACnetError (tvb, pinfo, bacapp_tree, offset, tmp); } static guint -fRejectPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset) +fRejectPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset) { /* BACnet-Reject-PDU */ /* ASHRAE 135-2001 20.1.8 */ proto_item *tc; proto_tree *bacapp_tree_control; - tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE); - bacapp_tree_control = proto_item_add_subtree(tc, 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); + 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 *bacapp_tree, guint offset) +fAbortPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset) { /* BACnet-Abort-PDU */ /* ASHRAE 135-2001 20.1.9 */ proto_item *tc; proto_tree *bacapp_tree_control; - tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE); - bacapp_tree_control = proto_item_add_subtree(tc, 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); + 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 +static guint +do_the_dissection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + guint8 flag, bacapp_type; + guint offset = 0; + + flag = (gint) tvb_get_guint8(tvb, 0); + bacapp_type = (flag >> 4) & 0x0f; + + if (tvb == NULL || tree == NULL) { + return 0; + } + + /* ASHRAE 135-2001 20.1.1 */ + switch (bacapp_type) { + case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: /* BACnet-Confirmed-Service-Request */ + offset = fConfirmedRequestPDU(tvb, pinfo, tree, offset); + break; + case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST: /* BACnet-Unconfirmed-Request-PDU */ + offset = fUnconfirmedRequestPDU(tvb, pinfo, tree, offset); + break; + case BACAPP_TYPE_SIMPLE_ACK: /* BACnet-Simple-Ack-PDU */ + offset = fSimpleAckPDU(tvb, pinfo, tree, offset); + break; + case BACAPP_TYPE_COMPLEX_ACK: /* BACnet-Complex-Ack-PDU */ + offset = fComplexAckPDU(tvb, pinfo, tree, offset); + break; + case BACAPP_TYPE_SEGMENT_ACK: /* BACnet-SegmentAck-PDU */ + offset = fSegmentAckPDU(tvb, pinfo, tree, offset); + break; + case BACAPP_TYPE_ERROR: /* BACnet-Error-PDU */ + offset = fErrorPDU(tvb, pinfo, tree, offset); + break; + case BACAPP_TYPE_REJECT: /* BACnet-Reject-PDU */ + offset = fRejectPDU(tvb, pinfo, tree, offset); + break; + case BACAPP_TYPE_ABORT: /* BACnet-Abort-PDU */ + offset = fAbortPDU(tvb, pinfo, tree, offset); + break; + } + return offset; +} + +static void dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { - gint8 tmp, bacapp_type; - tvbuff_t *next_tvb; + guint8 flag, bacapp_type; + guint save_fragmented = FALSE, data_offset = 0, bacapp_apdu_size = fGetMaxAPDUSize(0), fragment = FALSE; + tvbuff_t* new_tvb = NULL; guint offset = 0; - guint8 bacapp_service, bacapp_reason; - guint8 bacapp_invoke_id; + guint8 bacapp_seqno = 0; + guint8 bacapp_service, bacapp_reason, bacapp_prop_win_size; + guint8 bacapp_invoke_id = 0; proto_item *ti; - proto_tree *bacapp_tree; - - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU"); - if (check_col(pinfo->cinfo, COL_INFO)) - col_add_str(pinfo->cinfo, COL_INFO, "BACnet APDU "); - - tmp = (gint) tvb_get_guint8(tvb, 0); - bacapp_type = (tmp >> 4) & 0x0f; + proto_tree *bacapp_tree = NULL; + + gint svc; + proto_item *tt = 0; + gint8 ack = 0; + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU"); + col_clear (pinfo->cinfo, COL_INFO); + + flag = tvb_get_guint8(tvb, 0); + bacapp_type = (flag >> 4) & 0x0f; /* show some descriptive text in the INFO column */ - if (check_col(pinfo->cinfo, COL_INFO)) + col_add_fstr(pinfo->cinfo, COL_INFO, "%-16s", + val_to_str(bacapp_type, BACnetTypeName, "# unknown APDU #")); + + switch (bacapp_type) { - col_clear(pinfo->cinfo, COL_INFO); - col_add_str(pinfo->cinfo, COL_INFO, - val_to_str(bacapp_type, BACnetTypeName, "#### unknown APDU ##### ")); - switch (bacapp_type) - { - case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: - /* segmented messages have 2 additional bytes */ - if (tmp & BACAPP_SEGMENTED_REQUEST) - { - bacapp_invoke_id = tvb_get_guint8(tvb, offset + 4); - bacapp_service = tvb_get_guint8(tvb, offset + 5); - } - else - { - bacapp_invoke_id = tvb_get_guint8(tvb, offset + 2); - bacapp_service = tvb_get_guint8(tvb, offset + 3); - } - col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s", - bacapp_invoke_id, - val_to_str(bacapp_service, - BACnetConfirmedServiceChoice, - bacapp_unknown_service_str)); - break; - case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST: - bacapp_service = tvb_get_guint8(tvb, offset + 1); - col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", - val_to_str(bacapp_service, - BACnetUnconfirmedServiceChoice, - bacapp_unknown_service_str)); - break; - case BACAPP_TYPE_SIMPLE_ACK: + case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: + /* segmented messages have 2 additional bytes */ + if (flag & BACAPP_SEGMENTED_REQUEST) + { + fragment = TRUE; + ack = 0; + bacapp_apdu_size = fGetMaxAPDUSize(tvb_get_guint8(tvb, offset + 1)); /* has 16 values, reserved are 50 Bytes */ + bacapp_invoke_id = tvb_get_guint8(tvb, offset + 2); + bacapp_seqno = tvb_get_guint8(tvb, offset + 3); + bacapp_prop_win_size = tvb_get_guint8(tvb, offset + 4); + bacapp_service = tvb_get_guint8(tvb, offset + 5); + data_offset = 6; + + } + else + { + bacapp_invoke_id = tvb_get_guint8(tvb, offset + 2); + bacapp_service = tvb_get_guint8(tvb, offset + 3); + } + col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", + val_to_str(bacapp_service, + BACnetConfirmedServiceChoice, + bacapp_unknown_service_str),bacapp_invoke_id); + break; + case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST: + bacapp_service = tvb_get_guint8(tvb, offset + 1); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", + val_to_str(bacapp_service, + BACnetUnconfirmedServiceChoice, + bacapp_unknown_service_str)); + break; + case BACAPP_TYPE_SIMPLE_ACK: + bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); + bacapp_service = tvb_get_guint8(tvb, offset + 2); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */ + val_to_str(bacapp_service, + BACnetConfirmedServiceChoice, + bacapp_unknown_service_str), bacapp_invoke_id); + break; + case BACAPP_TYPE_COMPLEX_ACK: + /* segmented messages have 2 additional bytes */ + if (flag & BACAPP_SEGMENTED_REQUEST) + { + fragment = TRUE; + ack = 1; + bacapp_apdu_size = fGetMaxAPDUSize(0); /* has minimum of 50 Bytes */ bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); - bacapp_service = tvb_get_guint8(tvb, offset + 2); - col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s", - bacapp_invoke_id, - val_to_str(bacapp_service, - BACnetConfirmedServiceChoice, - bacapp_unknown_service_str)); - break; - case BACAPP_TYPE_COMPLEX_ACK: - /* segmented messages have 2 additional bytes */ - if (tmp & BACAPP_SEGMENTED_REQUEST) - { - bacapp_invoke_id = tvb_get_guint8(tvb, offset + 3); - bacapp_service = tvb_get_guint8(tvb, offset + 4); - } - else - { - bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); - bacapp_service = tvb_get_guint8(tvb, offset + 2); - } - col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s", - bacapp_invoke_id, - val_to_str(bacapp_service, - BACnetConfirmedServiceChoice, - bacapp_unknown_service_str)); - break; - case BACAPP_TYPE_SEGMENT_ACK: - /* nothing more to add */ - break; - case BACAPP_TYPE_ERROR: + bacapp_seqno = tvb_get_guint8(tvb, offset + 2); + bacapp_prop_win_size = tvb_get_guint8(tvb, offset + 3); + bacapp_service = tvb_get_guint8(tvb, offset + 4); + data_offset = 5; + } + else + { bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); bacapp_service = tvb_get_guint8(tvb, offset + 2); - col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s", - bacapp_invoke_id, - val_to_str(bacapp_service, - BACnetConfirmedServiceChoice, - bacapp_unknown_service_str)); - break; - case BACAPP_TYPE_REJECT: - bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); - bacapp_reason = tvb_get_guint8(tvb, offset + 2); - col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s", - bacapp_invoke_id, - val_to_split_str(bacapp_reason, - 64, - BACnetRejectReason, - ASHRAE_Reserved_Fmt, - Vendor_Proprietary_Fmt)); + } + col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */ + val_to_str(bacapp_service, + BACnetConfirmedServiceChoice, + bacapp_unknown_service_str), bacapp_invoke_id); + break; + case BACAPP_TYPE_SEGMENT_ACK: + /* nothing more to add */ + break; + case BACAPP_TYPE_ERROR: + bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); + bacapp_service = tvb_get_guint8(tvb, offset + 2); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */ + val_to_str(bacapp_service, + BACnetConfirmedServiceChoice, + bacapp_unknown_service_str), bacapp_invoke_id); + break; + case BACAPP_TYPE_REJECT: + bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); + bacapp_reason = tvb_get_guint8(tvb, offset + 2); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */ + val_to_split_str(bacapp_reason, + 64, + BACnetRejectReason, + ASHRAE_Reserved_Fmt, + Vendor_Proprietary_Fmt), bacapp_invoke_id); + break; + case BACAPP_TYPE_ABORT: + bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); + bacapp_reason = tvb_get_guint8(tvb, offset + 2); + col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */ + val_to_split_str(bacapp_reason, + 64, + BACnetAbortReason, + ASHRAE_Reserved_Fmt, + Vendor_Proprietary_Fmt), bacapp_invoke_id); + break; + /* UNKNOWN */ + default: + /* nothing more to add */ + break; + } + + save_fragmented = pinfo->fragmented; + + if (tree) { + + ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); + + if (!fragment) + offset = do_the_dissection(tvb,pinfo,bacapp_tree); + else + fStartConfirmed(tvb, pinfo, bacapp_tree, offset, ack, &svc, &tt); + /* not resetting the offset so the remaining can be done */ + } + + if (fragment) { /* fragmented */ + fragment_data *frag_msg = NULL; + + new_tvb = NULL; + pinfo->fragmented = TRUE; + + frag_msg = fragment_add_seq_check(tvb, data_offset, pinfo, + bacapp_invoke_id, /* ID for fragments belonging together */ + msg_fragment_table, /* list of message fragments */ + msg_reassembled_table, /* list of reassembled messages */ + bacapp_seqno, /* fragment sequence number */ + tvb_reported_length_remaining(tvb, data_offset), /* fragment length - to the end */ + flag & BACAPP_MORE_SEGMENTS); /* Last fragment reached? */ + new_tvb = process_reassembled_data(tvb, data_offset, pinfo, + "Reassembled BACapp", frag_msg, &msg_frag_items, + NULL, tree); + + if (new_tvb) { /* Reassembled */ + col_append_str(pinfo->cinfo, COL_INFO, + " (Message Reassembled)"); + } else { /* Not last packet of reassembled Short Message */ + col_append_fstr(pinfo->cinfo, COL_INFO, + " (Message fragment %u)", bacapp_seqno); + } + if (new_tvb) { /* take it all */ + switch (bacapp_type) + { + case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: + fContinueConfirmedRequestPDU(new_tvb, pinfo, bacapp_tree, 0, svc); break; - case BACAPP_TYPE_ABORT: - bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); - bacapp_reason = tvb_get_guint8(tvb, offset + 2); - col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s", - bacapp_invoke_id, - val_to_split_str(bacapp_reason, - 64, - BACnetAbortReason, - ASHRAE_Reserved_Fmt, - Vendor_Proprietary_Fmt)); + case BACAPP_TYPE_COMPLEX_ACK: + fContinueComplexAckPDU(new_tvb, pinfo, bacapp_tree, 0, svc); break; - /* UNKNOWN */ - default: - /* nothing more to add */ + default: + /* do nothing */ break; + } + /* } */ } } - - if (tree) { - ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE); - bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); - /* ASHRAE 135-2001 20.1.1 */ - switch (bacapp_type) { - case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: /* BACnet-Confirmed-Service-Request */ - offset = fConfirmedRequestPDU(tvb, bacapp_tree, offset); - break; - case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST: /* BACnet-Unconfirmed-Request-PDU */ - offset = fUnconfirmedRequestPDU(tvb, bacapp_tree, offset); - break; - case BACAPP_TYPE_SIMPLE_ACK: /* BACnet-Simple-Ack-PDU */ - offset = fSimpleAckPDU(tvb, bacapp_tree, offset); - break; - case BACAPP_TYPE_COMPLEX_ACK: /* BACnet-Complex-Ack-PDU */ - offset = fComplexAckPDU(tvb, bacapp_tree, offset); - break; - case BACAPP_TYPE_SEGMENT_ACK: /* BACnet-SegmentAck-PDU */ - offset = fSegmentAckPDU(tvb, bacapp_tree, offset); - break; - case BACAPP_TYPE_ERROR: /* BACnet-Error-PDU */ - offset = fErrorPDU(tvb, bacapp_tree, offset); - break; - case BACAPP_TYPE_REJECT: /* BACnet-Reject-PDU */ - offset = fRejectPDU(tvb, bacapp_tree, offset); - break; - case BACAPP_TYPE_ABORT: /* BACnet-Abort-PDU */ - offset = fAbortPDU(tvb, bacapp_tree, offset); - break; - } - } - - next_tvb = tvb_new_subset(tvb,offset,-1,tvb_length_remaining(tvb,offset)); - call_dissector(data_handle,next_tvb, pinfo, tree); + pinfo->fragmented = save_fragmented; + +} + +static void +bacapp_init_routine(void) +{ + fragment_table_init(&msg_fragment_table); + reassembled_table_init(&msg_reassembled_table); +} + +static guint32 +fConvertXXXtoUTF8 (gchar *in, gsize *inbytesleft, gchar *out, gsize *outbytesleft, const gchar *fromcoding) +{ + guint32 i; + GIConv icd; + + if ((icd = g_iconv_open ("UTF-8", fromcoding)) != (GIConv) -1) { + i = (guint32) g_iconv (icd, &in, inbytesleft, &out, outbytesleft); + /* g_iconv incremented 'out'; now ensure it's NULL terminated */ + out[0] = '\0'; + + g_iconv_close (icd); + return i; + } + + uni_to_string(in,*inbytesleft,out); + out[*inbytesleft] = '\0'; + *outbytesleft -= *inbytesleft; + *inbytesleft = 0; + + return 0; +} + +static void +uni_to_string(char * data, gsize str_length, char *dest_buf) +{ + gint i; + guint16 c_char; + gsize length_remaining = 0; + + length_remaining = str_length; + dest_buf[0] = '\0'; + if(str_length == 0) + { + return; + } + for ( i = 0; i < (gint) str_length; i++ ) + { + c_char = data[i]; + if (c_char<0x20 || c_char>0x7e) + { + if (c_char != 0x00) + { + c_char = '.'; + dest_buf[i] = c_char & 0xff; + } + else + { + i--; + str_length--; + } + } + else + { + dest_buf[i] = c_char & 0xff; + } + length_remaining--; + + if(length_remaining==0) + { + dest_buf[i+1] = '\0'; + return; + } + } + if (i < 0) { + i = 0; + } + dest_buf[i] = '\0'; + return; } void @@ -5626,15 +9025,15 @@ proto_register_bacapp(void) static hf_register_info hf[] = { { &hf_bacapp_type, { "APDU Type", "bacapp.type", - FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, "APDU Type", HFILL } + FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, NULL, HFILL } }, { &hf_bacapp_pduflags, { "PDU Flags", "bacapp.pduflags", - FT_UINT8, BASE_HEX, NULL, 0x0f, "PDU Flags", HFILL } + FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL } }, { &hf_bacapp_SEG, { "Segmented Request", "bacapp.segmented_request", - FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, "Segmented Request", HFILL } + FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, NULL, HFILL } }, { &hf_bacapp_MOR, { "More Segments", "bacapp.more_segments", @@ -5646,43 +9045,55 @@ proto_register_bacapp(void) }, { &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 } + FT_UINT8, BASE_DEC, VALS(BACnetMaxAPDULengthAccepted), 0x0f, NULL, HFILL } }, { &hf_bacapp_response_segments, { "Max Response Segments accepted", "bacapp.response_segments", - FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0x70, "Max Response Segments accepted", HFILL } + FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0x70, NULL, HFILL } }, { &hf_bacapp_objectType, { "Object Type", "bacapp.objectType", - FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, "Object Type", HFILL } + FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, NULL, HFILL } }, { &hf_bacapp_instanceNumber, { "Instance Number", "bacapp.instance_number", - FT_UINT32, BASE_DEC, NULL, 0x003fffff, "Instance Number", HFILL } + FT_UINT32, BASE_DEC, NULL, 0x003fffff, NULL, HFILL } + }, + { &hf_BACnetPropertyIdentifier, + { "Property Identifier", "bacapp.property_identifier", + FT_UINT32, BASE_DEC, VALS(BACnetPropertyIdentifier), 0, NULL, HFILL } + }, + { &hf_BACnetVendorIdentifier, + { "Vendor Identifier", "bacapp.vendor_identifier", + FT_UINT16, BASE_DEC, VALS(BACnetVendorIdentifiers), 0, NULL, HFILL } + }, + { &hf_BACnetRestartReason, + { "Restart Reason", "bacapp.restart_reason", + FT_UINT8, BASE_DEC, VALS(BACnetRestartReason), 0, NULL, HFILL } }, { &hf_bacapp_invoke_id, { "Invoke ID", "bacapp.invoke_id", - FT_UINT8, BASE_DEC, NULL, 0, "Invoke ID", HFILL } + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_sequence_number, { "Sequence Number", "bacapp.sequence_number", - FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL } + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_window_size, { "Proposed Window Size", "bacapp.window_size", - FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL } + FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_service, { "Service Choice", "bacapp.confirmed_service", - FT_UINT8, BASE_DEC, VALS(BACnetConfirmedServiceChoice), 0x00, "Service Choice", HFILL } + FT_UINT8, BASE_DEC, VALS(BACnetConfirmedServiceChoice), 0x00, NULL, HFILL } }, { &hf_bacapp_uservice, { "Unconfirmed Service Choice", "bacapp.unconfirmed_service", - FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, "Unconfirmed Service Choice", HFILL } + FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, NULL, HFILL } }, { &hf_bacapp_NAK, { "NAK", "bacapp.NAK", - FT_BOOLEAN, 8, NULL, 0x02, "negativ ACK", HFILL } + FT_BOOLEAN, 8, NULL, 0x02, "negative ACK", HFILL } }, { &hf_bacapp_SRV, { "SRV", "bacapp.SRV", @@ -5690,88 +9101,129 @@ proto_register_bacapp(void) }, { &hf_BACnetRejectReason, { "Reject Reason", "bacapp.reject_reason", - FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, "Reject Reason", HFILL } + FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, NULL, HFILL } }, { &hf_BACnetAbortReason, { "Abort Reason", "bacapp.abort_reason", - FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 0x00, "Abort Reason", HFILL } + FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 0x00, NULL, HFILL } }, { &hf_bacapp_vpart, { "BACnet APDU variable part:", "bacapp.variable_part", - FT_NONE, 0, NULL, 0, "BACnet APDU variable part", HFILL } + FT_NONE, BASE_NONE, NULL, 0, "BACnet APDU variable part", HFILL } }, { &hf_bacapp_tag, { "BACnet Tag", "bacapp.tag", - FT_BYTES, BASE_HEX, NULL, 0, - "BACnet Tag", HFILL } + FT_BYTES, BASE_NONE, NULL, 0, + NULL, HFILL } }, { &hf_BACnetApplicationTagNumber, { "Application Tag Number", "bacapp.application_tag_number", FT_UINT8, BASE_DEC, VALS(&BACnetApplicationTagNumber), 0xF0, - "Application Tag Number", HFILL } + NULL, HFILL } }, { &hf_BACnetContextTagNumber, { "Context Tag Number", "bacapp.context_tag_number", FT_UINT8, BASE_DEC, NULL, 0xF0, - "Context Tag Number", HFILL } + NULL, HFILL } }, { &hf_BACnetExtendedTagNumber, { "Extended Tag Number", "bacapp.extended_tag_number", FT_UINT8, BASE_DEC, NULL, 0, - "Extended Tag Number", HFILL } + NULL, HFILL } }, { &hf_BACnetNamedTag, { "Named Tag", "bacapp.named_tag", FT_UINT8, BASE_DEC, VALS(&BACnetTagNames), 0x07, - "Named Tag", HFILL } + NULL, HFILL } }, { &hf_BACnetCharacterSet, { "String Character Set", "bacapp.string_character_set", FT_UINT8, BASE_DEC, VALS(&BACnetCharacterSet),0, - "String Character Set", HFILL } + NULL, HFILL } }, { &hf_BACnetTagClass, { "Tag Class", "bacapp.tag_class", - FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, "Tag Class", HFILL } + FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, NULL, HFILL } }, { &hf_bacapp_tag_lvt, { "Length Value Type", "bacapp.LVT", FT_UINT8, BASE_DEC, NULL, 0, - "Length Value Type", HFILL } + NULL, HFILL } }, { &hf_bacapp_tag_value8, { "Tag Value", "bacapp.tag_value8", FT_UINT8, BASE_DEC, NULL, 0, - "Tag Value", HFILL } + NULL, HFILL } }, { &hf_bacapp_tag_value16, { "Tag Value 16-bit", "bacapp.tag_value16", FT_UINT16, BASE_DEC, NULL, 0, - "Tag Value 16-bit", HFILL } + NULL, HFILL } }, { &hf_bacapp_tag_value32, { "Tag Value 32-bit", "bacapp.tag_value32", FT_UINT32, BASE_DEC, NULL, 0, - "Tag Value 32-bit", HFILL } + NULL, HFILL } }, { &hf_bacapp_tag_ProcessId, { "ProcessIdentifier", "bacapp.processId", FT_UINT32, BASE_DEC, NULL, 0, "Process Identifier", HFILL } }, + { &hf_bacapp_tag_IPV4, + { "IPV4", "bacapp.IPV4", + FT_IPv4, BASE_NONE, NULL, 0, "IP-Address", HFILL } + }, + { &hf_bacapp_tag_IPV6, + { "IPV6", "bacapp.IPV6", + FT_IPv6, BASE_NONE, NULL, 0, "IP-Address", HFILL } + }, + { &hf_bacapp_tag_PORT, + { "Port", "bacapp.Port", + FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } + }, { &hf_bacapp_tag_initiatingObjectType, { "ObjectType", "bacapp.objectType", FT_UINT16, BASE_DEC, VALS(BACnetObjectType), 0x00, "Object Type", HFILL } }, + {&hf_msg_fragments, + {"Message fragments", "bacapp.fragments", + FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + {&hf_msg_fragment, + {"Message fragment", "bacapp.fragment", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + {&hf_msg_fragment_overlap, + {"Message fragment overlap", "bacapp.fragment.overlap", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + {&hf_msg_fragment_overlap_conflicts, + {"Message fragment overlapping with conflicting data", + "bacapp.fragment.overlap.conflicts", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + {&hf_msg_fragment_multiple_tails, + {"Message has multiple tail fragments", + "bacapp.fragment.multiple_tails", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + {&hf_msg_fragment_too_long_fragment, + {"Message fragment too long", "bacapp.fragment.too_long_fragment", + FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + {&hf_msg_fragment_error, + {"Message defragmentation error", "bacapp.fragment.error", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + {&hf_msg_reassembled_in, + {"Reassembled in", "bacapp.reassembled.in", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + {&hf_msg_reassembled_length, + {"Reassembled BACapp length", "bacapp.reassembled.length", + FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } } }; static gint *ett[] = { &ett_bacapp, @@ -5779,13 +9231,18 @@ proto_register_bacapp(void) &ett_bacapp_tag, &ett_bacapp_list, &ett_bacapp_value, + &ett_msg_fragment, + &ett_msg_fragments + }; + proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU", - "BACapp", "bacapp"); + "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); + register_init_routine (&bacapp_init_routine); } @@ -5795,33 +9252,3 @@ proto_reg_handoff_bacapp(void) data_handle = find_dissector("data"); } -guint32 -fConvertXXXtoUTF8 (const guint8 *in, size_t *inbytesleft, guint8 *out, size_t *outbytesleft, const gchar *fromcoding) -{ /* I don't want to let in and out be modified */ -#ifdef HAVE_CONFIG_H -#if HAVE_ICONV_H - guint32 i; - iconv_t icd; - const guint8 *inp = in; - guint8 *outp = out; - const guint8 **inpp = &inp; - guint8 **outpp = &outp; - - if ((icd = iconv_open ("UTF-8", fromcoding)) != (iconv_t) -1) { - i = iconv (icd, (char**) inpp, inbytesleft, (char**) outpp, outbytesleft); - *outpp[0] = '\0'; - iconv_close (icd); - return i; - } - -#endif -#endif - - memcpy (out, in, *inbytesleft); - out[*inbytesleft] = '\0'; - *outbytesleft -= *inbytesleft; - *inbytesleft = 0; - - return 0; -} -