/* 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 * Enhanced by Felix Kraemer, 2010, , * Sauter-Cumulus GmbH, Freiburg * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "config.h" #include #include #include #include #include #include #include #include "packet-bacapp.h" static int bacapp_tap = -1; /* formerly bacapp.h contains definitions and forward declarations */ /* 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 #define BACAPP_MAX_RECURSION_DEPTH 100 // Arbitrary /** * 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to **/ /** * 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fConfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @return modified offset */ static guint fUnsignedTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); /** * 20.2.5, adds the label with max 64Bit signed Integer Value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @return modified offset */ static guint fSignedTag(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @param lvt length of String * @return modified offset */ static guint fOctetString(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, guint32 lvt); /** * 20.2.12, adds the label with Date Value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @return modified offset */ static guint fDate(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); /** * 20.2.13, adds the label with Time Value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @return modified offset */ static guint fTime(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @return modified offset */ static guint fObjectIdentifier(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); /** * BACnet-Confirmed-Service-Request ::= CHOICE { * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param service_choice the 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param service_choice the 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fAtomicWriteFileAck(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param subtree the sub tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fCreateObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset); /** * CreateObject-Request ::= BACnetObjectIdentifier * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fCreateObjectAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * DeleteObject-Request ::= SEQUENCE { * ObjectIdentifier BACnetObjectIdentifer * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param subtree the sub tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param subtree the sub tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fDeviceCommunicationControlRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * ConfirmedPrivateTransfer-Request ::= SEQUENCE { * vendorID [0] Unsigned, * serviceNumber [1] Unsigned, * serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fReinitializeDeviceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * VTOpen-Request ::= SEQUENCE { * vtClass BACnetVTClass, * localVTSessionIdentifier Unsigned8 * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fVtOpenRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * VTOpen-ACK ::= SEQUENCE { * remoteVTSessionIdentifier Unsigned8 * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fVtDataAck(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fAuthenticateRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * Authenticate-ACK ::= SEQUENCE { * modifiedRandomNumber Unsigned32, * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fRequestKeyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * Unconfirmed-Service-Request ::= CHOICE { * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param service_choice the 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fUnconfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * TimeSynchronization-Request ::= SEQUENCE { * BACnetDateTime * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fTimeSynchronizationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * UTCTimeSynchronization-Request ::= SEQUENCE { * BACnetDateTime * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fUTCTimeSynchronizationRequest(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fWhoIsRequest(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param service the 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param tag_match the 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fAddress(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetAddressBinding ::= SEQUENCE { * deviceObjectID BACnetObjectIdentifier * deviceAddress BacnetAddress * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fAddressBinding(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetCalendarEntry ::= CHOICE { * date [0] Date, * dateRange [1] BACnetDateRange, * weekNDay [2] BacnetWeekNday * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fCalendarEntry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetClientCOV ::= CHOICE { * real-increment REAL, * default-increment NULL * } * @param tvb the tv buffer of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fDailySchedule(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetHealth ::= SEQUENCE { * timestamp [0] BACnetDateTime, * result [1] Error, * property [2] BACnetPropertiyIdentifier OPTIONAL, * details [3] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fHealth(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetSCFailedConnectionRequest ::= SEQUENCE { * timestamp [0] BACnetDateTime, * peer-address [1] BACnetHostNPort, * peer-vmac [2] OCTET STRING (SIZE(6)) * peer-uuid [3] OCTET STRING (SIZE(16)) * error [4] Error OPTIONAL * error-details [5] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fSCFailedConnectionRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetSCDirectConnection ::= SEQUENCE { * uri [0] CharacterString * connection-state [1] BACnetSCConnectionState, * connect-timestamp [2] BACnetDateTime, * disconnect-timestamp [3] BACnetDateTime, * peer-address [4] BACnetHostNPort, * peer-vmac [5] OCTET STRING (SIZE(6)) * peer-uuid [6] OCTET STRING (SIZE(16)) * error [7] Error OPTIONAL * error-details [8] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fSCDirectConnection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetSCHubConnection ::= SEQUENCE { * connection-state [0] BACnetSCConnectionState, * connect-timestamp [1] BACnetDateTime, * disconnect-timestamp [2] BACnetDateTime, * error [3] Error OPTIONAL * error-details [4] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fSCHubConnection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetSCHubFunctionConnection ::= SEQUENCE { * connection-state [0] BACnetSCConnectionState, * connect-timestamp [1] BACnetDateTime, * disconnect-timestamp [2] BACnetDateTime, * peer-address [3] BACnetHostNPort, * peer-vmac [4] OCTET STRING (SIZE(6)) * peer-uuid [5] OCTET STRING (SIZE(16)) * error [6] Error OPTIONAL * error-details [7] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fSCHubFunctionConnection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetWeeklySchedule ::= SEQUENCE { * week-schedule SENQUENCE SIZE (7) OF BACnetDailySchedule * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fDateRange(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetDateTime ::= SEQUENCE { * date Date, * time Time * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @return modified offset */ static guint fDateTime(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fDeviceObjectPropertyReference(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetObjectPropertyReference ::= SEQUENCE { * objectIdentifier [0] BACnetObjectIdentifier, * propertyIdentifier [1] BACnetPropertyIdentifier, * propertyArrayIndex [2] Unsigend OPTIONAL, * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fObjectPropertyReference(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetDeviceObjectReference ::= SEQUENCE { * deviceIdentifier [0] BACnetObjectIdentifier OPTIONAL, * objectIdentifier [1] BACnetObjectIdentifier * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fDeviceObjectReference(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetEventParameter ::= CHOICE { * change-of-bitstring [0] SEQUENCE { * time-delay [0] Unsigned, * bitmask [1] BIT STRING, * list-of-bitstring-values [2] SEQUENCE OF BIT STRING * }, * change-of-state [1] SEQUENCE { * time-delay [0] Unsigned, * list-of-values [1] SEQUENCE OF BACnetPropertyStates * }, * change-of-value [2] SEQUENCE { * time-delay [0] Unsigned, * cov-criteria [1] CHOICE { * bitmask [0] BIT STRING, * referenced-property-increment [1] REAL * } * }, * command-failure [3] SEQUENCE { * time-delay [0] Unsigned, * feedback-property-reference [1] BACnetDeviceObjectPropertyReference * }, * floating-limit [4] SEQUENCE { * time-delay [0] Unsigned, * setpoint-reference [1] BACnetDeviceObjectPropertyReference, * low-diff-limit [2] REAL, * high-diff-limit [3] REAL, * deadband [4] REAL * }, * out-of-range [5] SEQUENCE { * time-delay [0] Unsigned, * low-limit [1] REAL, * high-limit [2] REAL, * deadband [3] REAL * }, * -- context tag 7 is deprecated * 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 * }, * extended [9] SEQUENCE { * vendor-id [0] Unsigned16, * extended-event-type [1] Unsigned, * parameters [2] SEQUENCE OF CHOICE { * null NULL, * real REAL, * integer Unsigned, * boolean BOOLEAN, * double Double, * octet OCTET STRING, * bitstring BIT STRING, * enum ENUMERATED, * reference [0] BACnetDeviceObjectPropertyReference * } * }, * buffer-ready [10] SEQUENCE { * notification-threshold [0] Unsigned, * previous-notification-count [1] Unsigned32 * }, * unsigned-range [11] SEQUENCE { * time-delay [0] Unsigned, * low-limit [1] Unsigned, * high-limit [2] Unsigned, * } * -- context tag 12 is reserved for future addenda * access-event [13] SEQUENCE { * list-of-access-events [0] SEQUENCE OF BACnetAccessEvent, * access-event-time-reference [1] BACnetDeviceObjectPropertyReference * } * double-out-of-range [14] SEQUENCE { * time-delay [0] Unsigned, * low-limit [1] Double, * high-limit [2] Double, * deadband [3] Double * } * signed-out-of-range [15] SEQUENCE { * time-delay [0] Unsigned, * low-limit [1] INTEGER, * high-limit [2] INTEGER, * deadband [3] Unsigned * } * unsigned-out-of-range [16] SEQUENCE { * time-delay [0] Unsigned, * low-limit [1] Unsigned, * high-limit [2] Unsigned, * deadband [3] Unsigned * } * change-of-characterstring [17] SEQUENCE { * time-delay [0] Unsigned, * list-of-alarm-values [1] SEQUENCE OF CharacterString, * } * change-of-status-flags [18] SEQUENCE { * time-delay [0] Unsigned, * selected-flags [1] BACnetStatusFlags * } * } * @param tvb the tv buffer of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fEventParameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetLogRecord ::= SEQUENCE { * timestamp [0] BACnetDateTime, * logDatum [1] CHOICE { * log-status [0] BACnetLogStatus, * boolean-value [1] BOOLEAN, * real-value [2] REAL, * enum-value [3] ENUMERATED, -- Optionally limited to 32 bits * unsigned-value [4] Unsigned, -- Optionally limited to 32 bits * signed-value [5] INTEGER, -- Optionally limited to 32 bits * bitstring-value [6] BIT STRING, -- Optionally limited to 32 bits * null-value [7] NULL, * failure [8] Error, * time-change [9] REAL, * any-value [10] ABSTRACT-SYNTAX.&Type -- Optional * } * statusFlags [2] BACnetStatusFlags OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fLogRecord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetEventLogRecord ::= SEQUENCE { * timestamp [0] BACnetDateTime, * logDatum [1] CHOICE { * log-status [0] BACnetLogStatus, * notification [1] ConfirmedEventNotification-Request, * time-change [2] REAL, * } * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fEventLogRecord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fLogMultipleRecord(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 [3] REAL * }, * complex-event-type [6] SEQUENCE OF BACnetPropertyValue, * -- complex tag 7 is deprecated * change-of-life-safety [8] SEQUENCE { * new-state [0] BACnetLifeSafetyState, * new-mode [1] BACnetLifeSafetyState * status-flags [2] BACnetStatusFlags, * operation-expected [3] BACnetLifeSafetyOperation * }, * extended [9] SEQUENCE { * vendor-id [0] Unsigned16, * extended-event-type [1] Unsigned, * parameters [2] SEQUENCE OF CHOICE { * null NULL, * real REAL, * integer Unsigned, * boolean BOOLEAN, * double Double, * octet OCTET STRING, * bitstring BIT STRING, * enum ENUMERATED, * propertyValue [0] BACnetDeviceObjectPropertyValue * } * }, * buffer-ready [10] SEQUENCE { * buffer-property [0] BACnetDeviceObjectPropertyReference, * previous-notification[1] Unsigned32, * current-notification [2] BACneUnsigned32tDateTime * }, * unsigned-range [11] SEQUENCE { * exceeding-value [0] Unsigned, * status-flags [1] BACnetStatusFlags, * exceeded-limit [2] Unsigned * }, * -- context tag 12 is reserved for future addenda * access-event [13] SEQUENCE { * access-event [0] BACnetAccessEvent, * status-flags [1] BACnetStatusFlags, * access-event-tag [2] Unsigned, * access-event-time [3] BACnetTimeStamp, * access-credential [4] BACnetDeviceObjectReference, * authentication-factor [5] BACnetAuthenticationFactor OPTIONAL * }, * double-out-of-range [14] SEQUENCE { * exceeding-value [0] Double, * status-flags [1] BACnetStatusFlags * deadband [2] Double, * exceeded-limit [3] Double * }, * signed-out-of-range [15] SEQUENCE { * exceeding-value [0] INTEGER, * status-flags [1] BACnetStatusFlags * deadband [2] Unsigned, * exceeded-limit [3] INTEGER * }, * unsigned-out-of-range [16] SEQUENCE { * exceeding-value [0] Unsigned, * status-flags [1] BACnetStatusFlags * deadband [2] Unsigned, * exceeded-limit [3] Unsigned * }, * change-of-characterstring [17] SEQUENCE { * changed-value [0] CharacterString, * status-flags [1] BACnetStatusFlags * alarm-value [2] CharacterString * }, * change-of-status-flags [18] SEQUENCE { * present-value [0] ABSTRACT-SYNTAX.&Type OPTIONAL, * -- depends on referenced property * referenced-flags [1] BACnetStatusFlags * }, * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fObjectPropertyValue(tvbuff_t *tvb, proto_tree *tree, guint offset); #endif /** * BACnetPriorityArray ::= SEQUENCE SIZE (16) OF BACnetPriorityValue * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fBACnetPropertyReference(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 list); 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fRecipientProcess(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fCOVSubscription(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 the tv buffer of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param label the label of this item * @return modified offset */ static guint fTimeStamp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); static guint fEventTimeStamps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * BACnetTimeValue ::= SEQUENCE { * time Time, * value ABSTRACT-SYNTAX.&Type -- any primitive datatype, complex types cannot be decoded * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fWeekNDay(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param subtree the subtree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param subtree the sub tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data "TestyVirtualBuffer" * @param offset the offset in the tvb 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 the tv buffer of the current data = "TestyVirtualBuffer" * @param pinfo the packet info of the current data = packet info * @param offset the offset in the tvb = 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, packet_info *pinfo, guint offset, guint8 *tag_no, guint8* class_tag, guint32 *lvt); /** * adds processID with max 32Bit unsigned Integer Value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fProcessId(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * adds present value to the tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param vs enum of string values when applicable * @param split_val enum index * @param type present value datatype enum * @return modified offset */ static guint fPresentValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const value_string *vs, guint32 split_val, BacappPresentValueType type); /** * adds event type to the tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fEventType(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * adds notify type to the tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fNotifyType(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * adds next_state with max 32Bit unsigned Integer Value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fToState(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * adds from_state with max 32Bit unsigned Integer Value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fFromState(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * adds object_name string value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fObjectName(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * wrapper function for fCharacterStringBase * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fCharacterString(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); /** * adds string value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @param present_val_dissect exposes string as present_value property * @param object_name_dissect exposes string as object_name property * @return modified offset */ static guint fCharacterStringBase(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, gboolean present_val_dissect, gboolean object_name_dissect); /** * adds timeSpan with max 32Bit unsigned Integer Value to tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fTimeSpan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); /** * BACnet Application PDUs chapter 21 * BACnetPropertyIdentifier::= ENUMERATED { * @see bacapp_property_identifier * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fPropertyArrayIndex(tvbuff_t *tvb, packet_info *pinfo, 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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param subtree the sub tree to append this item to * @param offset the offset in the tvb * @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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * Adds error-code from BACnet-Error to the tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fErrorCode(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * Adds error-class from BACnet-Error to the tree * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fErrorClass(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 the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset * @todo beautify this ugly construct */ static guint fContextTaggedValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); /** * realizes some ABSTRACT-SYNTAX.&Type * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @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, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *src); static guint fBitStringTagVSBase(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *src, gboolean present_val_dissect); static guint fFaultParameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fEventNotificationSubscription(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fLightingCommand(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *lable); static guint fColorCommand(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, guint offset, const gchar* lable); static guint fXyColor(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, guint offset, const gchar* lable); static guint fTimerStateChangeValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fHostNPort(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *lable); static guint fBDTEntry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *lable); static guint fFDTEntry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *lable); static guint fRouterEntry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fVMACEntry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fValueSource(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fAssignedLandingCalls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fLandingCallStatus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fLandingDoorStatus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fCOVMultipleSubscription(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fNameValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fNameValueCollection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fAuthenticationFactor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fAuthenticationFactorFormat(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fAuthenticationPolicy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fAccessRule(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fChannelValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label); static guint fPropertyAccessResult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fNetworkSecurityPolicy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fSecurityKeySet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fAuditLogRecord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fStageLimitValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); static guint fObjectSelector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); /** * register_bacapp */ void proto_register_bacapp(void); /* <<<< formerly bacapp.h */ /* reassembly table for segmented messages */ static reassembly_table msg_reassembly_table; /* some necessary forward function prototypes */ static guint 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"; /* Usage: no format specifiers */ static const char ASHRAE_Reserved_Fmt[] = "(%d) Reserved for Use by ASHRAE"; static const char Vendor_Proprietary_Fmt[] = "(%d) Vendor Proprietary Value"; static const value_string BACnetTypeName[] = { { 0, "Confirmed-REQ"}, { 1, "Unconfirmed-REQ"}, { 2, "Simple-ACK"}, { 3, "Complex-ACK"}, { 4, "Segment-ACK"}, { 5, "Error"}, { 6, "Reject"}, { 7, "Abort"}, { 0, NULL } }; static const true_false_string segments_follow = { "Segmented Request", "Unsegmented Request" }; static const true_false_string more_follow = { "More Segments Follow", "No More Segments Follow" }; static const true_false_string segmented_accept = { "Segmented Response accepted", "Segmented Response not accepted" }; static const true_false_string BACnetTagClass = { "Context Specific Tag", "Application Tag" }; static const value_string BACnetMaxSegmentsAccepted [] = { { 0, "Unspecified"}, { 1, "2 segments"}, { 2, "4 segments"}, { 3, "8 segments"}, { 4, "16 segments"}, { 5, "32 segments"}, { 6, "64 segments"}, { 7, "Greater than 64 segments"}, { 0, NULL } }; static const value_string BACnetMaxAPDULengthAccepted [] = { { 0, "Up to MinimumMessageSize (50 octets)"}, { 1, "Up to 128 octets"}, { 2, "Up to 206 octets (fits in a LonTalk frame)"}, { 3, "Up to 480 octets (fits in an ARCNET frame)"}, { 4, "Up to 1024 octets"}, { 5, "Up to 1476 octets (fits in an ISO 8802-3 frame)"}, { 6, "reserved by ASHRAE"}, { 7, "reserved by ASHRAE"}, { 8, "reserved by ASHRAE"}, { 9, "reserved by ASHRAE"}, { 10, "reserved by ASHRAE"}, { 11, "reserved by ASHRAE"}, { 12, "reserved by ASHRAE"}, { 13, "reserved by ASHRAE"}, { 14, "reserved by ASHRAE"}, { 15, "reserved by ASHRAE"}, { 0, NULL} }; static const value_string BACnetRejectReason [] = { { 0, "other"}, { 1, "buffer-overflow"}, { 2, "inconsistent-parameters"}, { 3, "invalid-parameter-data-type"}, { 4, "invalid-tag"}, { 5, "missing-required-parameter"}, { 6, "parameter-out-of-range"}, { 7, "too-many-arguments"}, { 8, "undefined-enumeration"}, { 9, "unrecognized-service"}, { 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"}, { 8, "activate-changes"}, { 0, NULL} }; static const value_string BACnetApplicationTagNumber [] = { { 0, "Null"}, { 1, "Boolean"}, { 2, "Unsigned Integer"}, { 3, "Signed Integer (2's complement notation)"}, { 4, "Real (ANSI/IEE-754 floating point)"}, { 5, "Double (ANSI/IEE-754 double precision floating point)"}, { 6, "Octet String"}, { 7, "Character String"}, { 8, "Bit String"}, { 9, "Enumerated"}, { 10, "Date"}, { 11, "Time"}, { 12, "BACnetObjectIdentifier"}, { 13, "reserved by ASHRAE"}, { 14, "reserved by ASHRAE"}, { 15, "reserved by ASHRAE"}, { 0, NULL} }; static const value_string BACnetAction [] = { { 0, "direct"}, { 1, "reverse"}, { 0, NULL} }; static const value_string BACnetAccessEvent [] = { { 0, "none"}, { 1, "granted"}, { 2, "muster"}, { 3, "passback-detected"}, { 4, "duress"}, { 5, "trace"}, { 6, "lockout-max-attempts"}, { 7, "lockout-other"}, { 8, "lockout-relinquished"}, { 9, "lockout-by-higher-priority"}, { 10, "out-of-service"}, { 11, "out-of-service-relinquished"}, { 12, "accompaniment-by"}, { 13, "authentication-factor-read"}, { 14, "authorization-delayed"}, { 15, "verification-required"}, /* Enumerated values 128-511 are used for events * which indicate that access has been denied. */ { 128, "denied-deny-all"}, { 129, "denied-unknown-credential"}, { 130, "denied-authentication-unavailable"}, { 131, "denied-authentication-factor-timeout"}, { 132, "denied-incorrect-authentication-factor"}, { 133, "denied-zone-no-access-rights"}, { 134, "denied-point-no-access-rights"}, { 135, "denied-no-access-rights"}, { 136, "denied-out-of-time-range"}, { 137, "denied-threat-level"}, { 138, "denied-passback"}, { 139, "denied-unexpected-location-usage"}, { 140, "denied-max-attempts"}, { 141, "denied-lower-occupancy-limit"}, { 142, "denied-upper-occupancy-limit"}, { 143, "denied-authentication-factor-lost"}, { 144, "denied-authentication-factor-stolen"}, { 145, "denied-authentication-factor-damaged"}, { 146, "denied-authentication-factor-destroyed"}, { 147, "denied-authentication-factor-disabled"}, { 148, "denied-authentication-factor-error"}, { 149, "denied-credential-unassigned"}, { 150, "denied-credential-not-provisioned"}, { 151, "denied-credential-not-yet-active"}, { 152, "denied-credential-expired"}, { 153, "denied-credential-manual-disable"}, { 154, "denied-credential-lockout"}, { 155, "denied-credential-max-days"}, { 156, "denied-credential-max-uses"}, { 157, "denied-credential-inactivity"}, { 158, "denied-credential-disabled"}, { 159, "denied-no-accompaniment"}, { 160, "denied-incorrect-accompaniment"}, { 161, "denied-lockout"}, { 162, "denied-verification-failed"}, { 163, "denied-verification-timeout"}, { 164, "denied-other"}, { 0, NULL} /* Enumerated values 0-512 are reserved for definition by ASHRAE. Enumerated values 512-65535 may be used by others subject to procedures and constraints described in Clause 23. */ }; static const value_string BACnetAccessZoneOccupancyState[] = { { 0, "normal"}, { 1, "below-lower-limit"}, { 2, "at-lower-limit"}, { 3, "at-upper-limit"}, { 4, "above-upper-limit"}, { 5, "disabled"}, { 6, "not-supported"}, { 0, NULL} }; static const value_string BACnetAccessPassbackMode[] = { { 0, "passback-off" }, { 1, "hard-passback" }, { 2, "soft-passback" }, { 0, NULL } }; static const value_string BACnetAccessCredentialDisableReason[] = { { 0, "disabled" }, { 1, "disabled-needs-provisioning" }, { 2, "disabled-unassigned" }, { 3, "disabled-not-yet-active" }, { 4, "disabled-expired" }, { 5, "disabled-lockout" }, { 6, "disabled-max-days" }, { 7, "disabled-max-uses" }, { 8, "disabled-inactivity" }, { 9, "disabled-manual" }, { 0, NULL } }; static const value_string BACnetAccessUserType[] = { { 0, "asset" }, { 1, "group" }, { 2, "person" }, { 0, NULL } }; static const value_string BACnetWriteStatus[] = { { 0, "idle" }, { 1, "in-progress" }, { 2, "successful" }, { 3, "failed" }, { 0, NULL } }; static const value_string BACnetLightingTransition[] = { { 0, "none" }, { 1, "fade" }, { 2, "ramp" }, { 0, NULL } }; static const value_string BACnetSecurityLevel[] = { { 0, "incapable" }, { 1, "plain" }, { 2, "signed" }, { 3, "encrypted" }, { 4, "signed-end-to-end" }, { 5, "encrypted-end-to-end" }, { 0, NULL } }; static const value_string BACnetAccessCredentialDisable[] = { { 0, "none" }, { 1, "disable" }, { 2, "disable-manual" }, { 3, "disable-lockout" }, { 0, NULL } }; static const value_string BACnetAuthenticationStatus[] = { { 0, "not-ready" }, { 1, "ready" }, { 2, "disabled" }, { 3, "waiting-for-authentication-factor" }, { 4, "waiting-for-accompaniment" }, { 5, "waiting-for-verification" }, { 6, "in-progress" }, { 0, NULL } }; static const value_string BACnetAuthorizationMode[] = { { 0, "authorize" }, { 1, "grant-active" }, { 2, "deny-all" }, { 3, "verification-required" }, { 4, "authorization-delayed" }, { 5, "none" }, { 0, NULL } }; static const value_string BACnetAuthorizationExemption[] = { { 0, "passback" }, { 1, "occupancy-check" }, { 2, "access-rights" }, { 3, "lockout" }, { 4, "deny" }, { 5, "verification" }, { 6, "authorization-delay" }, { 0, NULL } }; static const value_string BACnetLightingInProgress[] = { { 0, "idle" }, { 1, "fade-active" }, { 2, "ramp-active" }, { 3, "not-controlled" }, { 4, "other" }, { 5, "trim-active" }, { 0, NULL } }; static const value_string BACnetColorOperationInProgress[] = { { 0, "idle" }, { 1, "fade-active" }, { 2, "ramp-active" }, { 3, "not-controlled" }, { 4, "other" }, { 0, NULL } }; static const value_string BACnetColorTransition[] = { { 0, "none" }, { 1, "fade" }, { 2, "ramp" }, { 0, NULL } }; static const value_string BACnetBinaryLightingPV[] = { { 0, "off" }, { 1, "on" }, { 2, "warn" }, { 3, "warn-off" }, { 4, "warn-relinquish" }, { 5, "stop" }, { 0, NULL } }; static const value_string BACnetBackupState[] = { { 0, "idle"}, { 1, "preparing-for-backup"}, { 2, "preparing-for-restore"}, { 3, "performing-a-backup"}, { 4, "performing-a-restore"}, { 5, "backup-failure"}, { 6, "restore-failure"}, { 0, NULL} }; static const value_string BACnetAcknowledgedTransitions[] = { { 0, "to-offnormal" }, { 1, "to-fault" }, { 2, "to-normal" }, { 0, NULL } }; static const value_string BACnetFileAccessMethod [] = { { 0, "record-access"}, { 1, "stream-access"}, { 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"}, { 1, "buffer-overflow"}, { 2, "invalid-apdu-in-this-state"}, { 3, "preempted-by-higher-priority-task"}, { 4, "segmentation-not-supported"}, { 5, "security-error"}, { 6, "insufficient-security"}, { 7, "window-size-out-of-range"}, { 8, "application-exceeded-reply-time"}, { 9, "out-of-resources"}, { 10, "tsm-timeout"}, { 11, "apdu-too-long"}, { 0, NULL} }; static const value_string BACnetIpMode [] = { { 0, "normal"}, { 1, "foreign"}, { 2, "bbmd"}, { 0, NULL} }; static const value_string BACnetNetworkPortCommand [] = { { 0, "idle"}, { 1, "discard-changes"}, { 2, "renew-fd-registration"}, { 3, "restart-slave-discovery"}, { 4, "renew-dhcp"}, { 5, "restart-autonegotiation"}, { 6, "disconnect"}, { 7, "restart-port"}, { 8, "generate-csr-file"}, { 9, "validate-changes"}, { 0, NULL} }; static const value_string BACnetNetworkNumberQuality [] = { { 0, "unknown"}, { 1, "learned"}, { 2, "learned-configured"}, { 3, "configured"}, { 0, NULL} }; static const value_string BACnetNetworkType [] = { { 0, "ethernet" }, { 1, "arcnet" }, { 2, "mstp" }, { 3, "ptp" }, { 4, "lontalk" }, { 5, "bacnet-ipv4" }, { 6, "zigbee" }, { 7, "virtual" }, { 8, "non-bacnet" }, { 9, "bacnet-ipv6" }, {10, "serial" }, {11, "secure-connect" }, { 0, NULL} }; static const value_string BACnetSCConnectionState [] = { { 0, "not-connected" }, { 1, "connected" }, { 2, "disconnected-with-errors" }, { 3, "failed-to-connect" }, { 0, NULL} }; static const value_string BACnetSCHubConnectorState [] = { { 0, "no-hub-connection" }, { 1, "connected-to-primary" }, { 2, "connected-to-failover" }, { 0, NULL} }; static const value_string BACnetLifeSafetyMode [] = { { 0, "off"}, { 1, "on"}, { 2, "test"}, { 3, "manned"}, { 4, "unmanned"}, { 5, "armed"}, { 6, "disarmed"}, { 7, "prearmed"}, { 8, "slow"}, { 9, "fast"}, { 10, "disconnected"}, { 11, "enabled"}, { 12, "disabled"}, { 13, "atomic-release-disabled"}, { 14, "default"}, { 15, "activated-oeo-alarm"}, { 16, "activated-oeo-evacuate"}, { 17, "activated-oeo-phase1-recall"}, { 18, "activated-oeo-unavailable"}, { 19, "deactivated"}, { 0, NULL} /* 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. */ }; static const value_string BACnetLifeSafetyOperation [] = { { 0, "none"}, { 1, "silence"}, { 2, "silence-audible"}, { 3, "silence-visual"}, { 4, "reset"}, { 5, "reset-alarm"}, { 6, "reset-fault"}, { 7, "unsilence"}, { 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 procedures and constraints described in Clause 23. */ }; static const value_string BACnetLifeSafetyState [] = { { 0, "quiet"}, { 1, "pre-alarm"}, { 2, "alarm"}, { 3, "fault"}, { 4, "fault-pre-alarm"}, { 5, "fault-alarm"}, { 6, "not-ready"}, { 7, "active"}, { 8, "tamper"}, { 9, "test-alarm"}, { 10, "test-active"}, { 11, "test-fault"}, { 12, "test-fault-alarm"}, { 13, "holdup"}, { 14, "duress"}, { 15, "tamper-alarm"}, { 16, "abnormal"}, { 17, "emergency-power"}, { 18, "delayed"}, { 19, "blocked"}, { 20, "local-alarm"}, { 21, "general-alarm"}, { 22, "supervisory"}, { 23, "test-supervisory"}, { 24, "non-default-mode"}, { 25, "oeo-unavailable"}, { 26, "oeo-alarm"}, { 27, "oeo-phase1-recall"}, { 28, "oeo-evacuate"}, { 29, "oeo-unaffected"}, { 30, "test-oeo-unavailable"}, { 31, "test-oeo-alarm"}, { 32, "test-oeo-phase1-recall"}, { 33, "test-oeo-evacuate"}, { 34, "test-oeo-unaffected"}, { 0, NULL} /* 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. */ }; static const value_string BACnetLimitEnable[] = { { 0, "low-limit" }, { 1, "high-limit" }, { 0, NULL } }; static const value_string BACnetTimerState [] = { { 0, "idle"}, { 1, "running"}, { 2, "expired"}, { 0, NULL} }; static const value_string BACnetTimerTransition [] = { { 0, "none"}, { 1, "idle-to-running"}, { 2, "running-to-idle"}, { 3, "running-to-running"}, { 4, "running-to-expired"}, { 5, "forced-to-expired"}, { 6, "expired-to-idle"}, { 7, "expired-to-running"}, { 0, NULL} }; static const value_string BACnetEscalatorFault [] = { { 0, "controller-fault"}, { 1, "drive-and-motor-fault"}, { 2, "mechanical-component-fault"}, { 3, "overspeed-fault"}, { 4, "power-supply-fault"}, { 5, "safety-device-fault"}, { 6, "controller-supply-fault"}, { 7, "drive-temperature-exceeded"}, { 8, "comb-plate-fault"}, { 0, NULL} }; static const value_string BACnetEscalatorMode [] = { { 0, "unknown"}, { 1, "stop"}, { 2, "up"}, { 3, "down"}, { 4, "inspection"}, { 5, "out-of-service"}, { 0, NULL} }; static const value_string BACnetEscalatorOperationDirection [] = { { 0, "unknown"}, { 1, "stopped"}, { 2, "up-rated-speed"}, { 3, "up-reduced-speed"}, { 4, "down-rated-speed"}, { 5, "down-reduced-speed"}, { 0, NULL} }; static const value_string BACnetLiftCarDirection [] = { { 0, "unknown"}, { 1, "none"}, { 2, "stopped"}, { 3, "up"}, { 4, "down"}, { 5, "up-and-down"}, { 0, NULL} }; static const value_string BACnetLiftCarDoorCommand [] = { { 0, "none"}, { 1, "open"}, { 2, "close"}, { 0, NULL} }; static const value_string BACnetLiftCarDriveStatus [] = { { 0, "unknown"}, { 1, "stationary"}, { 2, "braking"}, { 3, "accelerate"}, { 4, "decelerate"}, { 5, "rated-speed"}, { 6, "single-floor-jump"}, { 7, "two-floor-jump"}, { 8, "three-floor-jump"}, { 9, "multi-floor-jump"}, { 0, NULL} }; static const value_string BACnetLiftCarMode [] = { { 0, "unknown"}, { 1, "normal"}, { 2, "vip"}, { 3, "homing"}, { 4, "parking"}, { 5, "attendant-control"}, { 6, "firefighter-control"}, { 7, "emergency-power"}, { 8, "inspection"}, { 9, "cabinet-recall"}, { 10, "earthquake-operation"}, { 11, "fire-operation"}, { 12, "out-of-service"}, { 13, "occupant-evacuation"}, { 0, NULL} }; static const value_string BACnetLiftFault [] = { { 0, "controller-fault"}, { 1, "drive-and-motor-fault"}, { 2, "governor-and-safety-gear-fault"}, { 3, "lift-shaft-device-fault"}, { 4, "power-supply-fault"}, { 5, "safety-interlock-fault"}, { 6, "door-closing-fault"}, { 7, "door-opening-fault"}, { 8, "car-stopped-outside-landing-zone"}, { 9, "call-button-stuck"}, { 10, "start-failure"}, { 11, "controller-supply-fault"}, { 12, "self-test-failure"}, { 13, "runtime-limit-exceeded"}, { 14, "position-lost"}, { 15, "drive-temperature-exceeded"}, { 16, "load-measurement-fault"}, { 0, NULL} }; static const value_string BACnetLiftGroupMode [] = { { 0, "unknown"}, { 1, "normal"}, { 2, "down-peak"}, { 3, "two-way"}, { 4, "four-way"}, { 5, "emergency-power"}, { 6, "up-peak"}, { 0, NULL} }; static const value_string BACnetProtocolLevel [] = { { 0, "physical"}, { 1, "protocol"}, { 2, "bacnet-application"}, { 3, "non-bacnet-application"}, { 0, NULL} }; static const value_string BACnetRelationship [] = { { 0, "unknown"}, { 1, "default"}, { 2, "contains"}, { 3, "contained-by"}, { 4, "uses"}, { 5, "used-by"}, { 6, "commands"}, { 7, "commanded-by"}, { 8, "adjusts"}, { 9, "adjusted-by"}, { 10, "ingress"}, { 11, "egress"}, { 12, "supplies-air"}, { 13, "receives-air"}, { 14, "supplies-hot-air"}, { 15, "receives-hot-air"}, { 16, "supplies-cool-air"}, { 17, "receives-cool-air"}, { 18, "supplies-power"}, { 19, "receives-power"}, { 20, "supplies-gas"}, { 21, "receives-gas"}, { 22, "supplies-water"}, { 23, "receives-water"}, { 24, "supplies-hot-water"}, { 25, "receives-hot-water"}, { 26, "supplies-cool-water"}, { 27, "receives-cool-water"}, { 28, "supplies-steam"}, { 29, "receives-steam"}, { 0, NULL} }; static const value_string BACnetLightingOperation[] = { { 0, "none" }, { 1, "fade-to" }, { 2, "ramp-to" }, { 3, "step-up" }, { 4, "step-down" }, { 5, "step-on" }, { 6, "step-off" }, { 7, "warn" }, { 8, "warn-off" }, { 9, "warn-relinquish" }, { 10, "stop" }, { 0, NULL } }; static const value_string BACnetColorOperation[] = { { 0, "none" }, { 1, "fade-to-color" }, { 2, "fade-to-cct" }, { 3, "ramp-to-cct" }, { 4, "step-up-cct" }, { 5, "step-down-cct" }, { 6, "stop" }, { 0, NULL } }; static const value_string BACnetConfirmedServiceChoice[] = { { 0, "acknowledgeAlarm"}, { 1, "confirmedCOVNotification"}, { 2, "confirmedEventNotification"}, { 3, "getAlarmSummary"}, { 4, "getEnrollmentSummary"}, { 5, "subscribeCOV"}, { 6, "atomicReadFile"}, { 7, "atomicWriteFile"}, { 8, "addListElement"}, { 9, "removeListElement"}, { 10, "createObject"}, { 11, "deleteObject"}, { 12, "readProperty"}, { 13, "readPropertyConditional"}, { 14, "readPropertyMultiple"}, { 15, "writeProperty"}, { 16, "writePropertyMultiple"}, { 17, "deviceCommunicationControl"}, { 18, "confirmedPrivateTransfer"}, { 19, "confirmedTextMessage"}, { 20, "reinitializeDevice"}, { 21, "vtOpen"}, { 22, "vtClose"}, { 23, "vtData"}, { 24, "authenticate"}, { 25, "requestKey"}, { 26, "readRange"}, { 27, "lifeSafetyOperation"}, { 28, "subscribeCOVProperty"}, { 29, "getEventInformation"}, { 30, "subscribeCovPropertyMultiple"}, { 31, "confirmedCovNotificationMultiple"}, { 32, "confirmedAuditNotification"}, { 33, "auditLogQuery"}, { 0, NULL} }; static const value_string BACnetReliability [] = { { 0, "no-fault-detected"}, { 1, "no-sensor"}, { 2, "over-range"}, { 3, "under-range"}, { 4, "open-loop"}, { 5, "shorted-loop"}, { 6, "no-output"}, { 7, "unreliable-other"}, { 8, "process-error"}, { 9, "multi-state-fault"}, { 10, "configuration-error"}, { 11, "reserved for a future addendum"}, { 12, "communication-failure"}, { 13, "member-fault"}, { 14, "monitored-object-fault" }, { 15, "tripped"}, { 16, "lamp-failure"}, { 17, "activation-failure"}, { 18, "renew-dhcp-failure"}, { 19, "renew-fd-registration-failure"}, { 20, "restart-auto-negotiation-failure"}, { 21, "restart-failure"}, { 22, "proprietary-command-failure"}, { 23, "faults-listed"}, { 24, "referenced-object-fault"}, { 0, NULL} }; static const value_string BACnetRouterStatus[] = { { 0, "available" }, { 1, "busy" }, { 2, "disconnected" }, { 0, NULL } }; static const value_string BACnetUnconfirmedServiceChoice [] = { { 0, "i-Am"}, { 1, "i-Have"}, { 2, "unconfirmedCOVNotification"}, { 3, "unconfirmedEventNotification"}, { 4, "unconfirmedPrivateTransfer"}, { 5, "unconfirmedTextMessage"}, { 6, "timeSynchronization"}, { 7, "who-Has"}, { 8, "who-Is"}, { 9, "utcTimeSynchronization"}, { 10, "writeGroup"}, { 11, "unconfirmedCovNotificationMultiple"}, { 12, "unconfirmedAuditNotification"}, { 13, "who-am-I" }, { 14, "you-are" }, { 0, NULL} }; static const value_string BACnetObjectType [] = { { 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 */ { 31, "timer"}, { 32, "access-credential"}, { 33, "access-point"}, { 34, "access-rights"}, { 35, "access-user"}, { 36, "access-zone"}, { 37, "credential-data-input"}, { 38, "network-security"}, { 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"}, { 51, "notification-forwarder"}, { 52, "alert-enrollment"}, { 53, "channel"}, { 54, "lighting-output"}, { 55, "binary-lighting-output"}, { 56, "network-port"}, { 57, "elevator-group"}, { 58, "escalator"}, { 59, "lift"}, { 60, "staging"}, { 61, "audit-log"}, { 62, "audit-reporter"}, { 63, "color"}, { 64, "color-temperature"}, { 0, NULL} /* Enumerated values 0-127 are reserved for definition by ASHRAE. Enumerated values 128-1023 may be used by others subject to the procedures and constraints described in Clause 23. */ }; static const value_string BACnetEngineeringUnits [] = { { 0, "Sq Meters"}, { 1, "Sq Feet"}, { 2, "Milliamperes"}, { 3, "Amperes"}, { 4, "Ohms"}, { 5, "Volts"}, { 6, "Kilovolts"}, { 7, "Megavolts"}, { 8, "Volt Amperes"}, { 9, "Kilovolt Amperes"}, { 10, "Megavolt Amperes"}, { 11, "Volt Amperes Reactive"}, { 12, "Kilovolt Amperes Reactive"}, { 13, "Megavolt Amperes Reactive"}, { 14, "Degrees Phase"}, { 15, "Power Factor"}, { 16, "Joules"}, { 17, "Kilojoules"}, { 18, "Watt Hours"}, { 19, "Kilowatt Hours"}, { 20, "BTUs"}, { 21, "Therms"}, { 22, "Ton Hours"}, { 23, "Joules Per Kg Dry Air"}, { 24, "BTUs Per Pound Dry Air"}, { 25, "Cycles Per Hour"}, { 26, "Cycles Per Minute"}, { 27, "Hertz"}, { 28, "Grams Of Water Per Kilogram Dry Air"}, { 29, "Relative Humidity"}, { 30, "Millimeters"}, { 31, "Meters"}, { 32, "Inches"}, { 33, "Feed"}, { 34, "Watts Per Sq Foot"}, { 35, "Watts Per Sq meter"}, { 36, "Lumens"}, { 37, "Lux"}, { 38, "Foot Candles"}, { 39, "Kilograms"}, { 40, "Pounds Mass"}, { 41, "Tons"}, { 42, "Kgs per Second"}, { 43, "Kgs Per Minute"}, { 44, "Kgs Per Hour"}, { 45, "Pounds Mass Per Minute"}, { 46, "Pounds Mass Per Hour"}, { 47, "Watt"}, { 48, "Kilowatts"}, { 49, "Megawatts"}, { 50, "BTUs Per Hour"}, { 51, "Horsepower"}, { 52, "Tons Refrigeration"}, { 53, "Pascals"}, { 54, "Kilopascals"}, { 55, "Bars"}, { 56, "Pounds Force Per Square Inch"}, { 57, "Centimeters Of Water"}, { 58, "Inches Of Water"}, { 59, "Millimeters Of Mercury"}, { 60, "Centimeters Of Mercury"}, { 61, "Inches Of Mercury"}, { 62, "Degrees Celsius"}, { 63, "Degrees Kelvin"}, { 64, "Degrees Fahrenheit"}, { 65, "Degree Days Celsius"}, { 66, "Degree Days Fahrenheit"}, { 67, "Years"}, { 68, "Months"}, { 69, "Weeks"}, { 70, "Days"}, { 71, "Hours"}, { 72, "Minutes"}, { 73, "Seconds"}, { 74, "Meters Per Second"}, { 75, "Kilometers Per Hour"}, { 76, "Feed Per Second"}, { 77, "Feet Per Minute"}, { 78, "Miles Per Hour"}, { 79, "Cubic Feet"}, { 80, "Cubic Meters"}, { 81, "Imperial Gallons"}, { 82, "Liters"}, { 83, "US Gallons"}, { 84, "Cubic Feet Per Minute"}, { 85, "Cubic Meters Per Second"}, { 86, "Imperial Gallons Per Minute"}, { 87, "Liters Per Second"}, { 88, "Liters Per Minute"}, { 89, "US Gallons Per Minute"}, { 90, "Degrees Angular"}, { 91, "Degrees Celsius Per Hour"}, { 92, "Degrees Celsius Per Minute"}, { 93, "Degrees Fahrenheit Per Hour"}, { 94, "Degrees Fahrenheit Per Minute"}, { 95, "No Units"}, { 96, "Parts Per Million"}, { 97, "Parts Per Billion"}, { 98, "Percent"}, { 99, "Percent Per Second"}, { 100, "Per Minute"}, { 101, "Per Second"}, { 102, "Psi Per Degree Fahrenheit"}, { 103, "Radians"}, { 104, "Revolutions Per Min"}, { 105, "Currency1"}, { 106, "Currency2"}, { 107, "Currency3"}, { 108, "Currency4"}, { 109, "Currency5"}, { 110, "Currency6"}, { 111, "Currency7"}, { 112, "Currency8"}, { 113, "Currency9"}, { 114, "Currency10"}, { 115, "Sq Inches"}, { 116, "Sq Centimeters"}, { 117, "BTUs Per Pound"}, { 118, "Centimeters"}, { 119, "Pounds Mass Per Second"}, { 120, "Delta Degrees Fahrenheit"}, { 121, "Delta Degrees Kelvin"}, { 122, "Kilohms"}, { 123, "Megohms"}, { 124, "Millivolts"}, { 125, "Kilojoules Per Kg"}, { 126, "Megajoules"}, { 127, "Joules Per Degree Kelvin"}, { 128, "Joules Per Kg Degree Kelvin"}, { 129, "Kilohertz"}, { 130, "Megahertz"}, { 131, "Per Hour"}, { 132, "Milliwatts"}, { 133, "Hectopascals"}, { 134, "Millibars"}, { 135, "Cubic Meters Per Hour"}, { 136, "Liters Per Hour"}, { 137, "KWatt Hours Per Square Meter"}, { 138, "KWatt Hours Per Square Foot"}, { 139, "Megajoules Per Square Meter"}, { 140, "Megajoules Per Square Foot"}, { 141, "Watts Per Sq Meter Degree Kelvin"}, { 142, "Cubic Feet Per Second"}, { 143, "Percent Obstruction Per Foot"}, { 144, "Percent Obstruction Per Meter"}, { 145, "milliohms"}, { 146, "megawatt-hours"}, { 147, "kilo-btus"}, { 148, "mega-btus"}, { 149, "kilojoules-per-kilogram-dry-air"}, { 150, "megajoules-per-kilogram-dry-air"}, { 151, "kilojoules-per-degree-Kelvin"}, { 152, "megajoules-per-degree-Kelvin"}, { 153, "newton"}, { 154, "grams-per-second"}, { 155, "grams-per-minute"}, { 156, "tons-per-hour"}, { 157, "kilo-btus-per-hour"}, { 158, "hundredths-seconds"}, { 159, "milliseconds"}, { 160, "newton-meters"}, { 161, "millimeters-per-second"}, { 162, "millimeters-per-minute"}, { 163, "meters-per-minute"}, { 164, "meters-per-hour"}, { 165, "cubic-meters-per-minute"}, { 166, "meters-per-second-per-second"}, { 167, "amperes-per-meter"}, { 168, "amperes-per-square-meter"}, { 169, "ampere-square-meters"}, { 170, "farads"}, { 171, "henrys"}, { 172, "ohm-meters"}, { 173, "siemens"}, { 174, "siemens-per-meter"}, { 175, "teslas"}, { 176, "volts-per-degree-Kelvin"}, { 177, "volts-per-meter"}, { 178, "webers"}, { 179, "candelas"}, { 180, "candelas-per-square-meter"}, { 181, "degrees-Kelvin-per-hour"}, { 182, "degrees-Kelvin-per-minute"}, { 183, "joule-seconds"}, { 184, "radians-per-second"}, { 185, "square-meters-per-Newton"}, { 186, "kilograms-per-cubic-meter"}, { 187, "newton-seconds"}, { 188, "newtons-per-meter"}, { 189, "watts-per-meter-per-degree-Kelvin"}, { 190, "micro-siemens"}, { 191, "cubic-feet-per-hour"}, { 192, "us-gallons-per-hour"}, { 193, "kilometers"}, { 194, "micrometers"}, { 195, "grams"}, { 196, "milligrams"}, { 197, "milliliters"}, { 198, "milliliters-per-second"}, { 199, "decibels"}, { 200, "decibels-millivolt"}, { 201, "decibels-volt"}, { 202, "millisiemens"}, { 203, "watt-hours-reactive"}, { 204, "kilowatt-hours-reactive"}, { 205, "megawatt-hours-reactive"}, { 206, "millimeters-of-water"}, { 207, "per-mille"}, { 208, "grams-per-gram"}, { 209, "kilograms-per-kilogram"}, { 210, "grams-per-kilogram"}, { 211, "milligrams-per-gram"}, { 212, "milligrams-per-kilogram"}, { 213, "grams-per-milliliter"}, { 214, "grams-per-liter"}, { 215, "milligrams-per-liter"}, { 216, "micrograms-per-liter"}, { 217, "grams-per-cubic-meter"}, { 218, "milligrams-per-cubic-meter"}, { 219, "micrograms-per-cubic-meter"}, { 220, "nanograms-per-cubic-meter"}, { 221, "grams-per-cubic-centimeter"}, { 222, "becquerels"}, { 223, "kilobecquerels"}, { 224, "megabecquerels"}, { 225, "gray"}, { 226, "milligray"}, { 227, "microgray"}, { 228, "sieverts"}, { 229, "millisieverts"}, { 230, "microsieverts"}, { 231, "microsieverts-per-hour"}, { 232, "decibels-a"}, { 233, "nephelometric-turbidity-unit"}, { 234, "pH"}, { 235, "grams-per-square-meter"}, { 236, "minutes-per-degree-kelvin"}, { 237, "ohm-meter-squared-per-meter"}, { 238, "ampere-seconds"}, { 239, "volt-ampere-hours"}, { 240, "kilovolt-ampere-hours"}, { 241, "megavolt-ampere-hours"}, { 242, "volt-ampere-hours-reactive"}, { 243, "kilovolt-ampere-hours-reactive"}, { 244, "megavolt-ampere-hours-reactive"}, { 245, "volt-square-hours"}, { 246, "ampere-square-hours"}, { 247, "joule-per-hours"}, { 248, "cubic-feet-per-day"}, { 249, "cubic-meters-per-day"}, { 250, "watt-hours-per-cubic-meter"}, { 251, "joules-per-cubic-meter"}, { 252, "mole-percent"}, { 253, "pascal-seconds"}, { 254, "million-standard-cubic-feet-per-minute"}, { 255, "unassigned-unit-value-255"}, { 47808, "standard-cubic-feet-per-day"}, { 47809, "million-standard-cubic-feet-per-day"}, { 47810, "thousand-cubic-feet-per-day"}, { 47811, "thousand-standard-cubic-feet-per-day"}, { 47812, "pounds-mass-per-day"}, { 47813, "reserved-unit-47813"}, { 47814, "millirems"}, { 47815, "millirems-per-hour"}, { 47816, "degrees-lovibond"}, { 47817, "alcohol-by-volume"}, { 47818, "international-bittering-units"}, { 47819, "european-bitterness-units"}, { 47820, "degrees-plato"}, { 47821, "specific-gravity"}, { 47822, "european-brewing-convention"}, { 0, NULL} /* 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. */ }; static const value_string BACnetErrorCode [] = { { 0, "other"}, { 1, "authentication-failed"}, { 2, "configuration-in-progress"}, { 3, "device-busy"}, { 4, "dynamic-creation-not-supported"}, { 5, "file-access-denied"}, { 6, "incompatible-security-levels"}, { 7, "inconsistent-parameters"}, { 8, "inconsistent-selection-criterion"}, { 9, "invalid-data-type"}, { 10, "invalid-file-access-method"}, { 11, "invalid-file-start-position"}, { 12, "invalid-operator-name"}, { 13, "invalid-parameter-data-type"}, { 14, "invalid-time-stamp"}, { 15, "key-generation-error"}, { 16, "missing-required-parameter"}, { 17, "no-objects-of-specified-type"}, { 18, "no-space-for-object"}, { 19, "no-space-to-add-list-element"}, { 20, "no-space-to-write-property"}, { 21, "no-vt-sessions-available"}, { 22, "property-is-not-a-list"}, { 23, "object-deletion-not-permitted"}, { 24, "object-identifier-already-exists"}, { 25, "operational-problem"}, { 26, "password-failure"}, { 27, "read-access-denied"}, { 28, "security-not-supported"}, { 29, "service-request-denied"}, { 30, "timeout"}, { 31, "unknown-object"}, { 32, "unknown-property"}, { 33, "removed enumeration"}, { 34, "unknown-vt-class"}, { 35, "unknown-vt-session"}, { 36, "unsupported-object-type"}, { 37, "value-out-of-range"}, { 38, "vt-session-already-closed"}, { 39, "vt-session-termination-failure"}, { 40, "write-access-denied"}, { 41, "character-set-not-supported"}, { 42, "invalid-array-index"}, { 43, "cov-subscription-failed"}, { 44, "not-cov-property"}, { 45, "optional-functionality-not-supported"}, { 46, "invalid-configuration-data"}, { 47, "datatype-not-supported"}, { 48, "duplicate-name"}, { 49, "duplicate-object-id"}, { 50, "property-is-not-an-array"}, { 51, "abort - buffer - overflow" }, { 52, "abort - invalid - apdu - in - this - state" }, { 53, "abort - preempted - by - higher - priority - task" }, { 54, "abort - segmentation - not - supported" }, { 55, "abort - proprietary" }, { 56, "abort - other" }, { 57, "invalid - tag" }, { 58, "network - down" }, { 59, "reject - buffer - overflow" }, { 60, "reject - inconsistent - parameters" }, { 61, "reject - invalid - parameter - data - type" }, { 62, "reject - invalid - tag" }, { 63, "reject - missing - required - parameter" }, { 64, "reject - parameter - out - of - range" }, { 65, "reject - too - many - arguments" }, { 66, "reject - undefined - enumeration" }, { 67, "reject - unrecognized - service" }, { 68, "reject - proprietary" }, { 69, "reject - other" }, { 70, "unknown - device" }, { 71, "unknown - route" }, { 72, "value - not - initialized" }, { 73, "invalid-event-state"}, { 74, "no-alarm-configured"}, { 75, "log-buffer-full"}, { 76, "logged-value-purged"}, { 77, "no-property-specified"}, { 78, "not-configured-for-triggered-logging"}, { 79, "unknown-subscription"}, { 80, "parameter-out-of-range"}, { 81, "list-element-not-found"}, { 82, "busy"}, { 83, "communication-disabled"}, { 84, "success"}, { 85, "access-denied"}, { 86, "bad-destination-address"}, { 87, "bad-destination-device-id"}, { 88, "bad-signature"}, { 89, "bad-source-address"}, { 90, "bad-timestamp"}, { 91, "cannot-use-key"}, { 92, "cannot-verify-message-id"}, { 93, "correct-key-revision"}, { 94, "destination-device-id-required"}, { 95, "duplicate-message"}, { 96, "encryption-not-configured"}, { 97, "encryption-required"}, { 98, "incorrect-key"}, { 99, "invalid-key-data"}, { 100, "key-update-in-progress"}, { 101, "malformed-message"}, { 102, "not-key-server"}, { 103, "security-not-configured"}, { 104, "source-security-required"}, { 105, "too-many-keys"}, { 106, "unknown-authentication-type"}, { 107, "unknown-key"}, { 108, "unknown-key-revision"}, { 109, "unknown-source-message"}, { 110, "not-router-to-dnet"}, { 111, "router-busy"}, { 112, "unknown-network-message"}, { 113, "message-too-long"}, { 114, "security-error"}, { 115, "addressing-error"}, { 116, "write-bdt-failed"}, { 117, "read-bdt-failed"}, { 118, "register-foreign-device-failed"}, { 119, "read-fdt-failed"}, { 120, "delete-fdt-entry-failed"}, { 121, "distribute-broadcast-failed"}, { 122, "unknown-file-size"}, { 123, "abort-apdu-too-long"}, { 124, "abort-application-exceeded-reply-time"}, { 125, "abort-out-of-resources"}, { 126, "abort-tsm-timeout"}, { 127, "abort-window-size-out-of-range"}, { 128, "file-full"}, { 129, "inconsistent-configuration"}, { 130, "inconsistent-object-type"}, { 131, "internal-error"}, { 132, "not-configured"}, { 133, "out-of-memory"}, { 134, "value-too-long"}, { 135, "abort-insufficient-security"}, { 136, "abort-security-error"}, { 137, "duplicate-entry"}, { 138, "invalid-value-in-this-state"}, { 139, "invalid-operation-in-this-state"}, { 140, "list-item-not-numbered"}, { 141, "list-item-not-timestamped"}, { 142, "invalid-data-encoding"}, { 143, "bvlc-function-unknown"}, { 144, "bvlc-proprietary-function-unknown"}, { 145, "header-encoding-error"}, { 146, "header-not-understood"}, { 147, "message-incomplete"}, { 148, "not-a-bacnet-sc-hub"}, { 149, "payload-expected"}, { 150, "unexpected-data"}, { 151, "node-duplicate-vmac"}, { 152, "http-unexpected-response-code"}, { 153, "http-no-upgrade"}, { 154, "http-resource-not-local"}, { 155, "http-proxy-authentication-failed"}, { 156, "http-response-timeout"}, { 157, "http-response-syntax-error"}, { 158, "http-response-value-error"}, { 159, "http-response-missing-header"}, { 160, "http-websocket-header-error"}, { 161, "http-upgrade-required"}, { 162, "http-upgrade-error"}, { 163, "http-temporary-unavailable"}, { 164, "http-not-a-server"}, { 165, "http-error"}, { 166, "websocket-scheme-not-supported"}, { 167, "websocket-unknown-control-message"}, { 168, "websocket-close-error"}, { 169, "websocket-closed-by-peer"}, { 170, "websocket-endpoint-leaves"}, { 171, "websocket-protocol-error"}, { 172, "websocket-data-not-accepted"}, { 173, "websocket-closed-abnormally"}, { 174, "websocket-data-inconsistent"}, { 175, "websocket-data-against-policy"}, { 176, "websocket-frame-too-long"}, { 177, "websocket-extension-missing"}, { 178, "websocket-request-unavailable"}, { 179, "websocket-error"}, { 180, "tls-client-certificate-error"}, { 181, "tls-server-certificate-error"}, { 182, "tls-client-authentication-failed"}, { 183, "tls-server-authentication-failed"}, { 184, "tls-client-certificate-expired"}, { 185, "tls-server-certificate-expired"}, { 186, "tls-client-certificate-revoked"}, { 187, "tls-server-certificate-revoked"}, { 188, "tls-error"}, { 189, "dns-unavailable"}, { 190, "dns-name-resolution-failed"}, { 191, "dns-resolver-failure"}, { 192, "dns-error"}, { 193, "tcp-connect-timeout"}, { 194, "tcp-connection-refused"}, { 195, "tcp-closed-by-local"}, { 196, "tcp-closed-other"}, { 197, "tcp-error"}, { 198, "ip-address-not-reachable"}, { 199, "ip-error"}, { 0, NULL} /* 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. */ }; static const value_string BACnetPropertyIdentifier [] = { { 0, "acked-transition"}, { 1, "ack-required"}, { 2, "action"}, { 3, "action-text"}, { 4, "active-text"}, { 5, "active-vt-session"}, { 6, "alarm-value"}, { 7, "alarm-values"}, { 8, "all"}, { 9, "all-writes-successful"}, { 10, "apdu-segment-timeout"}, { 11, "apdu-timeout"}, { 12, "application-software-version"}, { 13, "archive"}, { 14, "bias"}, { 15, "change-of-state-count"}, { 16, "change-of-state-time"}, { 17, "notification-class"}, { 18, "the property in this place was deleted"}, { 19, "controlled-variable-reference"}, { 20, "controlled-variable-units"}, { 21, "controlled-variable-value"}, { 22, "cov-increment"}, { 23, "datelist"}, { 24, "daylights-savings-status"}, { 25, "deadband"}, { 26, "derivative-constant"}, { 27, "derivative-constant-units"}, { 28, "description"}, { 29, "description-of-halt"}, { 30, "device-address-binding"}, { 31, "device-type"}, { 32, "effective-period"}, { 33, "elapsed-active-time"}, { 34, "error-limit"}, { 35, "event-enable"}, { 36, "event-state"}, { 37, "event-type"}, { 38, "exception-schedule"}, { 39, "fault-values"}, { 40, "feedback-value"}, { 41, "file-access-method"}, { 42, "file-size"}, { 43, "file-type"}, { 44, "firmware-revision"}, { 45, "high-limit"}, { 46, "inactive-text"}, { 47, "in-process"}, { 48, "instance-of"}, { 49, "integral-constant"}, { 50, "integral-constant-units"}, { 51, "issue-confirmed-notifications"}, { 52, "limit-enable"}, { 53, "list-of-group-members"}, { 54, "list-of-object-property-references"}, { 55, "list-of-session-keys"}, { 56, "local-date"}, { 57, "local-time"}, { 58, "location"}, { 59, "low-limit"}, { 60, "manipulated-variable-reference"}, { 61, "maximum-output"}, { 62, "max-apdu-length-accepted"}, { 63, "max-info-frames"}, { 64, "max-master"}, { 65, "max-pres-value"}, { 66, "minimum-off-time"}, { 67, "minimum-on-time"}, { 68, "minimum-output"}, { 69, "min-pres-value"}, { 70, "model-name"}, { 71, "modification-date"}, { 72, "notify-type"}, { 73, "number-of-APDU-retries"}, { 74, "number-of-states"}, { 75, "object-identifier"}, { 76, "object-list"}, { 77, "object-name"}, { 78, "object-property-reference"}, { 79, "object-type"}, { 80, "optional"}, { 81, "out-of-service"}, { 82, "output-units"}, { 83, "event-parameters"}, { 84, "polarity"}, { 85, "present-value"}, { 86, "priority"}, { 87, "priority-array"}, { 88, "priority-for-writing"}, { 89, "process-identifier"}, { 90, "program-change"}, { 91, "program-location"}, { 92, "program-state"}, { 93, "proportional-constant"}, { 94, "proportional-constant-units"}, { 95, "protocol-conformance-class"}, { 96, "protocol-object-types-supported"}, { 97, "protocol-services-supported"}, { 98, "protocol-version"}, { 99, "read-only"}, { 100, "reason-for-halt"}, { 101, "recipient"}, { 102, "recipient-list"}, { 103, "reliability"}, { 104, "relinquish-default"}, { 105, "required"}, { 106, "resolution"}, { 107, "segmentation-supported"}, { 108, "setpoint"}, { 109, "setpoint-reference"}, { 110, "state-text"}, { 111, "status-flags"}, { 112, "system-status"}, { 113, "time-delay"}, { 114, "time-of-active-time-reset"}, { 115, "time-of-state-count-reset"}, { 116, "time-synchronization-recipients"}, { 117, "units"}, { 118, "update-interval"}, { 119, "utc-offset"}, { 120, "vendor-identifier"}, { 121, "vendor-name"}, { 122, "vt-class-supported"}, { 123, "weekly-schedule"}, { 124, "attempted-samples"}, { 125, "average-value"}, { 126, "buffer-size"}, { 127, "client-cov-increment"}, { 128, "cov-resubscription-interval"}, { 129, "current-notify-time"}, { 130, "event-time-stamp"}, { 131, "log-buffer"}, { 132, "log-device-object-property"}, { 133, "enable"}, /* per ANSI/ASHRAE 135-2004 addendum B */ { 134, "log-interval"}, { 135, "maximum-value"}, { 136, "minimum-value"}, { 137, "notification-threshold"}, { 138, "previous-notify-time"}, { 139, "protocol-revision"}, { 140, "records-since-notification"}, { 141, "record-count"}, { 142, "start-time"}, { 143, "stop-time"}, { 144, "stop-when-full"}, { 145, "total-record-count"}, { 146, "valid-samples"}, { 147, "window-interval"}, { 148, "window-samples"}, { 149, "maximum-value-time-stamp"}, { 150, "minimum-value-time-stamp"}, { 151, "variance-value"}, { 152, "active-cov-subscriptions"}, { 153, "backup-failure-timeout"}, { 154, "configuration-files"}, { 155, "database-revision"}, { 156, "direct-reading"}, { 157, "last-restore-time"}, { 158, "maintenance-required"}, { 159, "member-of"}, { 160, "mode"}, { 161, "operation-expected"}, { 162, "setting"}, { 163, "silenced"}, { 164, "tracking-value"}, { 165, "zone-members"}, { 166, "life-safety-alarm-values"}, { 167, "max-segments-accepted"}, { 168, "profile-name"}, { 169, "auto-slave-discovery"}, { 170, "manual-slave-address-binding"}, { 171, "slave-address-binding"}, { 172, "slave-proxy-enable"}, { 173, "last-notify-record"}, /* bug 4117 */ { 174, "schedule-default"}, { 175, "accepted-modes"}, { 176, "adjust-value"}, { 177, "count"}, { 178, "count-before-change"}, { 179, "count-change-time"}, { 180, "cov-period"}, { 181, "input-reference"}, { 182, "limit-monitoring-interval"}, { 183, "logging-object"}, { 184, "logging-record"}, { 185, "prescale"}, { 186, "pulse-rate"}, { 187, "scale"}, { 188, "scale-factor"}, { 189, "update-time"}, { 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-interval"}, { 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"}, /* enumeration values 223-225 are unassigned */ { 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"}, /* enumeration values 236-243 are unassigned */ { 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, "expiration-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 are unassigned */ { 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"}, { 327, "base-device-security-policy"}, { 328, "distribution-key-revision"}, { 329, "do-not-hide"}, { 330, "key-sets"}, { 331, "last-key-server"}, { 332, "network-access-security-policies"}, { 333, "packet-reorder-time"}, { 334, "security-pdu-timeout"}, { 335, "security-time-window"}, { 336, "supported-security-algorithms"}, { 337, "update-key-set-timeout"}, { 338, "backup-and-restore-state"}, { 339, "backup-preparation-time"}, { 340, "restore-completion-time"}, { 341, "restore-preparation-time"}, { 342, "bit-mask"}, /* addenda 135-2008w */ { 343, "bit-text"}, { 344, "is-utc"}, { 345, "group-members"}, { 346, "group-member-names"}, { 347, "member-status-flags"}, { 348, "requested-update-interval"}, { 349, "covu-period"}, { 350, "covu-recipients"}, { 351, "event-message-texts"}, { 352, "event-message-texts-config"}, { 353, "event-detection-enable"}, { 354, "event-algorithm-inhibit"}, { 355, "event-algorithm-inhibit-ref"}, { 356, "time-delay-normal"}, { 357, "reliability-evaluation-inhibit"}, { 358, "fault-parameters"}, { 359, "fault-type"}, { 360, "local-forwarding-only"}, { 361, "process-identifier-filter"}, { 362, "subscribed-recipients"}, { 363, "port-filter"}, { 364, "authorization-exemptions"}, { 365, "allow-group-delay-inhibit"}, { 366, "channel-number"}, { 367, "control-groups"}, { 368, "execution-delay"}, { 369, "last-priority"}, { 370, "write-status"}, { 371, "property-list"}, { 372, "serial-number"}, { 373, "blink-warn-enable"}, { 374, "default-fade-time"}, { 375, "default-ramp-rate"}, { 376, "default-step-increment"}, { 377, "egress-time"}, { 378, "in-progress"}, { 379, "instantaneous-power"}, { 380, "lighting-command"}, { 381, "lighting-command-default-priority"}, { 382, "max-actual-value"}, { 383, "min-actual-value"}, { 384, "power"}, { 385, "transition"}, { 386, "egress-active"}, { 387, "interface-value"}, { 388, "fault-high-limit"}, { 389, "fault-low-limit"}, { 390, "low-diff-limit"}, { 391, "strike-count"}, { 392, "time-of-strike-count-reset"}, { 393, "default-timeout"}, { 394, "initial-timeout"}, { 395, "last-state-change"}, { 396, "state-change-values"}, { 397, "timer-running"}, { 398, "timer-state"}, { 399, "apdu-length"}, { 400, "bacnet-ip-address"}, { 401, "bacnet-ip-default-gateway"}, { 402, "bacnet-ip-dhcp-enable"}, { 403, "bacnet-ip-dhcp-lease-time"}, { 404, "bacnet-ip-dhcp-lease-time-remaining"}, { 405, "bacnet-ip-dhcp-server"}, { 406, "bacnet-ip-dns-server"}, { 407, "bacnet-ip-global-address"}, { 408, "bacnet-ip-mode"}, { 409, "bacnet-ip-multicast-address"}, { 410, "bacnet-ip-nat-traversal"}, { 411, "bacnet-ip-subnet-mask"}, { 412, "bacnet-ip-udp-port"}, { 413, "bbmd-accept-fd-registrations"}, { 414, "bbmd-broadcast-distribution-table"}, { 415, "bbmd-foreign-device-table"}, { 416, "changes-pending"}, { 417, "command"}, { 418, "fd-bbmd-address"}, { 419, "fd-subscription-lifetime"}, { 420, "link-speed"}, { 421, "link-speeds"}, { 422, "link-speed-autonegotiate"}, { 423, "mac-address"}, { 424, "network-interface-name"}, { 425, "network-number"}, { 426, "network-number-quality"}, { 427, "network-type"}, { 428, "routing-table"}, { 429, "virtual-mac-address-table"}, { 430, "command-time-array"}, { 431, "current-command-priority"}, { 432, "last-command-time"}, { 433, "value-source"}, { 434, "value-source-array"}, { 435, "bacnet-ipv6-mode"}, { 436, "ipv6-address"}, { 437, "ipv6-prefix-length"}, { 438, "bacnet-ipv6-udp-port"}, { 439, "ipv6-default-gateway"}, { 440, "bacnet-ipv6-multicast-address"}, { 441, "ipv6-dns-server"}, { 442, "ipv6-auto-addressing-enable"}, { 443, "ipv6-dhcp-lease-time"}, { 444, "ipv6-dhcp-lease-time-remaining"}, { 445, "ipv6-dhcp-server"}, { 446, "ipv6-zone-index"}, { 447, "assigned-landing-calls"}, { 448, "car-assigned-direction"}, { 449, "car-door-command"}, { 450, "car-door-status"}, { 451, "car-door-text"}, { 452, "car-door-zone"}, { 453, "car-drive-status"}, { 454, "car-load"}, { 455, "car-load-units"}, { 456, "car-mode"}, { 457, "car-moving-direction"}, { 458, "car-position"}, { 459, "elevator-group"}, { 460, "energy-meter"}, { 461, "energy-meter-ref"}, { 462, "escalator-mode"}, { 463, "fault-signals"}, { 464, "floor-text"}, { 465, "group-id"}, { 466, "enumeration value 466 is unassigned"}, { 467, "group-mode"}, { 468, "higher-deck"}, { 469, "installation-id"}, { 470, "landing-calls"}, { 471, "landing-call-control"}, { 472, "landing-door-status"}, { 473, "lower-deck"}, { 474, "machine-room-id"}, { 475, "making-car-call"}, { 476, "next-stopping-floor"}, { 477, "operation-direction"}, { 478, "passenger-alarm"}, { 479, "power-mode"}, { 480, "registered-car-call"}, { 481, "active-cov-multiple-subscriptions"}, { 482, "protocol-level"}, { 483, "reference-port"}, { 484, "deployed-profile-location"}, { 485, "profile-location"}, { 486, "tags"}, { 487, "subordinate-node-types"}, { 488, "subordinate-tags"}, { 489, "subordinate-relationship"}, { 490, "default-subordinate-relationship"}, { 491, "represents"}, { 492, "default-present-value"}, { 493, "present-stage"}, { 494, "stages"}, { 495, "stage-names"}, { 496, "target-references"}, { 497, "audit-source-reporter"}, { 498, "audit-level"}, { 499, "audit-notification-recipient"}, { 500, "audit-priority-filter"}, { 501, "auditable-operations"}, { 502, "delete-on-forward"}, { 503, "maximum-send-delay"}, { 504, "monitored-objects"}, { 505, "send-now"}, { 506, "floor-number"}, { 507, "device-uuid"}, { 508, "additional-reference-ports"}, { 509, "certificate-signing-request-file"}, { 510, "command-validation-result"}, { 511, "issuer-certificate-files"}, { 4194304, "max-bvlc-length-accepted"}, { 4194305, "max-npdu-length-accepted"}, { 4194306, "operational-certificate-file"}, { 4194307, "current-health"}, { 4194308, "sc-connect-wait-timeout"}, { 4194309, "sc-direct-connect-accept-enable"}, { 4194310, "sc-direct-connect-accept-uris"}, { 4194311, "ssc-direct-connect-binding"}, { 4194312, "sc-direct-connect-connection-status"}, { 4194313, "sc-direct-connect-initiate-enable"}, { 4194314, "sc-disconnect-wait-timeout"}, { 4194315, "sc-failed-connection-request"}, { 4194316, "sc-failover-hub-connection-status"}, { 4194317, "sc-failover-hub-uri"}, { 4194318, "sc-hub-connector-state"}, { 4194319, "sc-hub-function-accept-uris"}, { 4194320, "sc-hub-function-binding"}, { 4194321, "sc-hub-function-connection-status"}, { 4194322, "sc-hub-function-enable"}, { 4194323, "sc-heartbeat-timeout"}, { 4194324, "sc-primary-hub-connection-status"}, { 4194325, "sc-primary-hub-uri"}, { 4194326, "sc-maximum-reconnect-time"}, { 4194327, "sc-minimum-reconnect-time"}, { 4194328, "color-override"}, { 4194329, "color-reference"}, { 4194330, "default-color"}, { 4194331, "default-color-temperature"}, { 4194332, "override-color-reference"}, { 4194334, "color-command"}, { 4194335, "high_end_trim"}, { 4194336, "low_end_trim"}, { 4194337, "trim_fade_time"}, { 0, NULL} /* 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. */ }; static const value_string BACnetBinaryPV [] = { { 0, "inactive"}, { 1, "active"}, { 0, NULL} }; #define ANSI_X3_4 0 /* ANSI X3.4, a/k/a "ASCII"; full UTF-8 since 2010 */ /* See, for example, ANSI/ASHRAE Addendum k to ANSI/ASHRAE Standard 135-2008 */ /* XXX - I've seen captures using this for ISO 8859-1 */ #define IBM_MS_DBCS 1 /* "IBM/Microsoft DBCS"; was there only one such DBCS? */ #define JIS_C_6226 2 /* JIS C 6226 */ #define ISO_10646_UCS4 3 /* ISO 10646 (UCS-4) - 4-byte Unicode */ #define ISO_10646_UCS2 4 /* ISO 10646 (UCS-2) - 2-byte Unicode Basic Multilingual Plane (not UTF-16, presumably) */ #define ISO_8859_1 5 /* ISO 8859-1 */ static const value_string BACnetCharacterSet [] = { { ANSI_X3_4, "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_8859_1, "ISO 8859-1"}, { 0, NULL} }; static const value_string BACnetStatusFlags [] = { { 0, "in-alarm"}, { 1, "fault"}, { 2, "overridden"}, { 3, "out-of-service"}, { 0, NULL} }; static const value_string BACnetMessagePriority [] = { { 0, "normal"}, { 1, "urgent"}, { 0, NULL} }; static const value_string BACnetAcknowledgementFilter [] = { { 0, "all"}, { 1, "acked"}, { 2, "not-acked"}, { 0, NULL} }; static const value_string BACnetResultFlags [] = { { 0, "firstitem"}, { 1, "lastitem"}, { 2, "moreitems"}, { 0, NULL} }; static const value_string BACnetRelationSpecifier [] = { { 0, "equal"}, { 1, "not-equal"}, { 2, "less-than"}, { 3, "greater-than"}, { 4, "less-than-or-equal"}, { 5, "greater-than-or-equal"}, { 0, NULL} }; static const value_string BACnetSelectionLogic [] = { { 0, "and"}, { 1, "or"}, { 2, "all"}, { 0, NULL} }; static const value_string BACnetEventStateFilter [] = { { 0, "offnormal"}, { 1, "fault"}, { 2, "normal"}, { 3, "all"}, { 4, "active"}, { 0, NULL} }; static const value_string BACnetEventTransitionBits [] = { { 0, "to-offnormal"}, { 1, "to-fault"}, { 2, "to-normal"}, { 0, NULL} }; static const value_string BACnetSegmentation [] = { { 0, "segmented-both"}, { 1, "segmented-transmit"}, { 2, "segmented-receive"}, { 3, "no-segmentation"}, { 0, NULL} }; static const value_string BACnetSilencedState [] = { { 0, "unsilenced"}, { 1, "audible-silenced"}, { 2, "visible-silenced"}, { 3, "all-silenced"}, { 0, NULL} }; static const value_string BACnetDeviceStatus [] = { { 0, "operational"}, { 1, "operational-read-only"}, { 2, "download-required"}, { 3, "download-in-progress"}, { 4, "non-operational"}, { 5, "backup-in-progress"}, { 0, NULL} }; static const value_string BACnetEnableDisable [] = { { 0, "enable"}, { 1, "disable"}, { 2, "disable-initiation"}, { 0, NULL} }; static const value_string months [] = { { 1, "January" }, { 2, "February" }, { 3, "March" }, { 4, "April" }, { 5, "May" }, { 6, "June" }, { 7, "July" }, { 8, "August" }, { 9, "September" }, { 10, "October" }, { 11, "November" }, { 12, "December" }, { 13, "odd month" }, { 14, "even month" }, { 255, "any month" }, { 0, NULL } }; static const value_string weekofmonth [] = { { 1, "days numbered 1-7" }, { 2, "days numbered 8-14" }, { 3, "days numbered 15-21" }, { 4, "days numbered 22-28" }, { 5, "days numbered 29-31" }, { 6, "last 7 days of this month" }, { 7, "any of 7 days prior to last 7 days of this month" }, { 8, "any of 7 days prior to last 14 days of this month" }, { 9, "any of 7 days prior to last 21 days of this month" }, { 255, "any week of this month" }, { 0, NULL } }; /* note: notification class object recipient-list uses different day-of-week enum */ static const value_string day_of_week [] = { { 1, "Monday" }, { 2, "Tuesday" }, { 3, "Wednesday" }, { 4, "Thursday" }, { 5, "Friday" }, { 6, "Saturday" }, { 7, "Sunday" }, { 255, "any day of week" }, { 0, NULL } }; static const value_string BACnetErrorClass [] = { { 0, "device" }, { 1, "object" }, { 2, "property" }, { 3, "resources" }, { 4, "security" }, { 5, "services" }, { 6, "vt" }, { 7, "communication" }, { 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. */ }; static const value_string BACnetVTClass [] = { { 0, "default-terminal" }, { 1, "ansi-x3-64" }, { 2, "dec-vt52" }, { 3, "dec-vt100" }, { 4, "dec-vt200" }, { 5, "hp-700-94" }, { 6, "ibm-3130" }, { 0, NULL } }; static const value_string BACnetEventType [] = { { 0, "change-of-bitstring" }, { 1, "change-of-state" }, { 2, "change-of-value" }, { 3, "command-failure" }, { 4, "floating-limit" }, { 5, "out-of-range" }, { 6, "complex-event-type" }, { 7, "(deprecated)buffer-ready" }, { 8, "change-of-life-safety" }, { 9, "extended" }, { 10, "buffer-ready" }, { 11, "unsigned-range" }, { 13, "access-event" }, { 14, "double-out-of-range"}, /* added with addenda 135-2008w */ { 15, "signed-out-of-range"}, { 16, "unsigned-out-of-range"}, { 17, "change-of-characterstring"}, { 18, "change-of-status-flags"}, { 19, "change-of-reliability" }, { 20, "none" }, { 21, "change-of-discrete-value"}, { 22, "change-of-timer"}, { 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. */ }; static const value_string BACnetEventState [] = { { 0, "normal" }, { 1, "fault" }, { 2, "offnormal" }, { 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 the procedures and constraints described in Clause 23. */ }; static const value_string BACnetLogStatus [] = { { 0, "log-disabled" }, { 1, "buffer-purged" }, { 2, "log-interrupted"}, { 0, NULL } }; static const value_string BACnetMaintenance [] = { { 0, "none" }, { 1, "periodic-test" }, { 2, "need-service-operational" }, { 3, "need-service-inoperative" }, { 0, NULL } }; static const value_string BACnetNotifyType [] = { { 0, "alarm" }, { 1, "event" }, { 2, "ack-notification" }, { 0, NULL } }; static const value_string BACnetServicesSupported [] = { { 0, "acknowledgeAlarm"}, { 1, "confirmedCOVNotification"}, { 2, "confirmedEventNotification"}, { 3, "getAlarmSummary"}, { 4, "getEnrollmentSummary"}, { 5, "subscribeCOV"}, { 6, "atomicReadFile"}, { 7, "atomicWriteFile"}, { 8, "addListElement"}, { 9, "removeListElement"}, { 10, "createObject"}, { 11, "deleteObject"}, { 12, "readProperty"}, { 13, "readPropertyConditional"}, { 14, "readPropertyMultiple"}, { 15, "writeProperty"}, { 16, "writePropertyMultiple"}, { 17, "deviceCommunicationControl"}, { 18, "confirmedPrivateTransfer"}, { 19, "confirmedTextMessage"}, { 20, "reinitializeDevice"}, { 21, "vtOpen"}, { 22, "vtClose"}, { 23, "vtData"}, { 24, "authenticate"}, { 25, "requestKey"}, { 26, "i-Am"}, { 27, "i-Have"}, { 28, "unconfirmedCOVNotification"}, { 29, "unconfirmedEventNotification"}, { 30, "unconfirmedPrivateTransfer"}, { 31, "unconfirmedTextMessage"}, { 32, "timeSynchronization"}, { 33, "who-Has"}, { 34, "who-Is"}, { 35, "readRange"}, { 36, "utcTimeSynchronization"}, { 37, "lifeSafetyOperation"}, { 38, "subscribeCOVProperty"}, { 39, "getEventInformation"}, { 40, "write-group"}, { 41, "subscribe-cov-property-multiple"}, { 42, "confirmed-cov-notification-multiple"}, { 43, "unconfirmed-cov-notification-multiple"}, { 44, "confirmed-audit-notification" }, { 45, "audit-log-query" }, { 46, "unconfirmed-audit-notification" }, { 0, NULL} }; static const value_string BACnetPropertyStates [] = { { 0, "boolean-value"}, { 1, "binary-value"}, { 2, "event-type"}, { 3, "polarity"}, { 4, "program-change"}, { 5, "program-state"}, { 6, "reason-for-halt"}, { 7, "reliability"}, { 8, "state"}, { 9, "system-status"}, { 10, "units"}, { 11, "unsigned-value"}, { 12, "life-safety-mode"}, { 13, "life-safety-state"}, { 14, "restart-reason"}, { 15, "door-alarm-state"}, { 16, "action"}, { 17, "door-secured-status"}, { 18, "door-status"}, { 19, "door-value"}, { 20, "file-access-method"}, { 21, "lock-status"}, { 22, "life-safety-operation"}, { 23, "maintenance"}, { 24, "node-type"}, { 25, "notify-type"}, { 26, "security-level"}, { 27, "shed-state"}, { 28, "silenced-state"}, { 29, "unknown-29"}, { 30, "access-event"}, { 31, "zone-occupancy-state"}, { 32, "access-credential-disable-reason"}, { 33, "access-credential-disable"}, { 34, "authentication-status"}, { 35, "unknown-35"}, { 36, "backup-state"}, { 37, "write-status"}, { 38, "lighting-in-progress"}, { 39, "lighting-operation"}, { 40, "lighting-transition"}, { 41, "signed-value"}, { 42, "unknown-42"}, { 43, "timer-state"}, { 44, "timer-transition"}, { 45, "bacnet-ip-mode"}, { 46, "network-port-command"}, { 47, "network-type"}, { 48, "network-number-quality"}, { 49, "escalator-operation-direction"}, { 50, "escalator-fault"}, { 51, "escalator-mode"}, { 52, "lift-car-direction"}, { 53, "lift-car-door-command"}, { 54, "lift-car-drive-status"}, { 55, "lift-car-mode"}, { 56, "lift-group-mode"}, { 57, "lift-fault"}, { 58, "protocol-level"}, { 59, "audit-level"}, { 60, "audit-operation"}, { 63, "extended-value"}, {256, "-- example-one"}, {257, "-- example-two"}, {258, "sc-connection-state"}, {259, "sc-hub-connecto-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, subject to the constraints described in Clause 23. */ }; static const value_string BACnetProgramError [] = { { 0, "normal"}, { 1, "load-failed"}, { 2, "internal"}, { 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 the procedures and constraints described in Clause 23. */ }; static const value_string BACnetProgramRequest [] = { { 0, "ready"}, { 1, "load"}, { 2, "run"}, { 3, "halt"}, { 4, "restart"}, { 5, "unload"}, { 0, NULL} }; static const value_string BACnetProgramState [] = { { 0, "idle"}, { 1, "loading"}, { 2, "running"}, { 3, "waiting"}, { 4, "halted"}, { 5, "unloading"}, { 0, NULL} }; static const value_string BACnetReinitializedStateOfDevice [] = { { 0, "coldstart"}, { 1, "warmstart"}, { 2, "start-backup"}, { 3, "end-backup"}, { 4, "start-restore"}, { 5, "end-restore"}, { 6, "abort-restore"}, { 7, "activate-changes"}, { 0, NULL} }; static const value_string BACnetPolarity [] = { { 0, "normal"}, { 1, "reverse"}, { 0, NULL} }; static const value_string BACnetTagNames[] = { { 5, "Extended Value" }, { 6, "Opening Tag" }, { 7, "Closing Tag" }, { 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 BACnetFaultType[] = { { 0, "none" }, { 1, "fault-characterstring" }, { 2, "fault-extended" }, { 3, "fault-life-safety" }, { 4, "fault-state" }, { 5, "fault-status-flags" }, { 6, "fault-out-of-range" }, { 7, "fault-listed" }, { 0, NULL } }; static const value_string BACnetNodeType [] = { { 0, "unknown" }, { 1, "system" }, { 2, "network" }, { 3, "device" }, { 4, "organizational" }, { 5, "area" }, { 6, "equipment" }, { 7, "point" }, { 8, "collection" }, { 9, "property" }, { 10, "functional" }, { 11, "other" }, { 12, "subsystem" }, { 13, "building" }, { 14, "floor" }, { 15, "section" }, { 16, "module" }, { 17, "tree" }, { 18, "member" }, { 19, "protocol" }, { 20, "room" }, { 21, "zone" }, { 0, NULL } }; static const value_string BACnetLoggingType [] = { { 0, "polled" }, { 1, "cov" }, { 2, "triggered" }, { 0, NULL } }; static const value_string BACnetDoorStatus [] = { { 0, "closed" }, { 1, "opened" }, { 2, "unknown" }, { 3, "door-fault" }, { 4, "unused" }, { 5, "none" }, { 6, "closing" }, { 7, "opening" }, { 8, "safety-locked" }, { 9, "limited-opened" }, { 0, NULL } }; static const value_string BACnetDoorValue[] = { { 0, "lock" }, { 1, "unlock" }, { 2, "pulse-unlock" }, { 3, "extended-pulse-unlock" }, { 0, NULL } }; static const value_string BACnetLockStatus [] = { { 0, "locked" }, { 1, "unlocked" }, { 2, "fault" }, { 3, "unknown" }, { 0, NULL } }; static const value_string BACnetDoorSecuredStatus [] = { { 0, "secured" }, { 1, "unsecured" }, { 2, "unknown" }, { 0, NULL } }; static const value_string BACnetDoorAlarmState [] = { { 0, "normal" }, { 1, "alarm" }, { 2, "door-open-too-long" }, { 3, "forced-open" }, { 4, "tamper" }, { 5, "door-fault" }, { 6, "lock-down" }, { 7, "free-access" }, { 8, "egress-open" }, { 0, NULL } }; static const value_string BACnetSecurityPolicy [] = { { 0, "plain-non-trusted"}, { 1, "plain-trusted"}, { 2, "signed-trusted"}, { 3, "encrypted-trusted"}, { 0, NULL } }; static const value_string BACnetAccumulatorStatus [] = { { 0, "normal" }, { 1, "starting" }, { 2, "recovered" }, { 3, "abnormal" }, { 4, "failed" }, { 0, NULL } }; static const value_string BACnetAuditLevel [] = { { 0, "none" }, { 1, "audit-all" }, { 2, "audit-config" }, { 3, "default" }, { 0, NULL } }; static const value_string BACnetAuditPriorityFilter [] = { { 1, "manual-life-safety" }, { 2, "automatic-life-safety" }, { 3, "priority-3" }, { 4, "priority-4" }, { 5, "critical-equipment-controls" }, { 6, "minimum-on-off" }, { 7, "priority-7" }, { 8, "manual-operator" }, { 9, "priority-9" }, { 10, "priority-10" }, { 11, "priority-11" }, { 12, "priority-12" }, { 13, "priority-13" }, { 14, "priority-14" }, { 15, "priority-15" }, { 16, "priority-16" }, { 0, NULL } }; static const value_string BACnetAuditOperation [] = { { 0, "read" }, { 1, "write" }, { 2, "create" }, { 3, "delete" }, { 4, "life-safety" }, { 5, "acknowledge-alarm" }, { 6, "device-disable-comm" }, { 7, "device-enable-comm" }, { 8, "device-reset" }, { 9, "device-backup" }, { 10, "device-restore" }, { 11, "subscription" }, { 12, "notification" }, { 13, "auditing-failure" }, { 14, "network-changes" }, { 15, "general" }, { 0, NULL } }; static const value_string BACnetSuccessFilter [] = { { 0, "all" }, { 1, "successes-only" }, { 2, "failures-only" }, { 0, NULL } }; /* These values are generated by tools/generate-bacnet-vendors.py from * https://bacnet.org/assigned-vendor-ids/ * Version: "As of November 27, 2023" */ static const value_string BACnetVendorIdentifiers [] = { { 0, "ASHRAE" }, { 1, "NIST" }, { 2, "The Trane Company" }, { 3, "Daikin Applied Americas" }, { 4, "PolarSoft" }, { 5, "Johnson Controls, Inc." }, { 6, "ABB (Formerly American Auto-Matrix)" }, { 7, "Siemens Schweiz AG (Formerly: Landis & Staefa Division Europe)" }, { 8, "Delta Controls" }, { 9, "Siemens Schweiz AG" }, { 10, "Schneider Electric" }, { 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, "Siemens Schweiz AG (Formerly: 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 Building Technologies Limited" }, { 34, "Notifier" }, { 35, "Reliable Controls Corporation" }, { 36, "Tridium Inc." }, { 37, "MSA Safety" }, { 38, "Silicon Energy" }, { 39, "Kieback & Peter GmbH & Co KG" }, { 40, "Anacon Systems, Inc." }, { 41, "Systems Controls & Instruments, LLC" }, { 42, "Acuity Brands Lighting, Inc." }, { 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, LLC" }, { 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 Gebäudetechnik AG Bereich NetServ" }, { 74, "KNX Association cvba" }, { 75, "Institute of Electrical Installation Engineers of Japan (IEIEJ)" }, { 76, "Nohmi Bosai, Ltd." }, { 77, "Carel Industries S.p.A." }, { 78, "UTC Fire & Security España, S.L." }, { 79, "Hochiki Corporation" }, { 80, "Fr. Sauter AG" }, { 81, "Matsushita Electric Works, Ltd." }, { 82, "Mitsubishi Electric Corporation, Inazawa Works" }, { 83, "Mitsubishi Heavy Industries, Ltd." }, { 84, "Xylem, Inc." }, { 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 Gebäudeautomation GmbH" }, { 110, "eZi Controls" }, { 111, "Leviton Manufacturing" }, { 112, "Fujitsu Limited" }, { 113, "Vertiv (Formerly 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, "Lenze Americas (Formerly: 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, "Blue Ridge Technologies" }, { 133, "Veris Industries" }, { 134, "Centaurus Prime" }, { 135, "Sand Network Systems" }, { 136, "Regulvar, Inc." }, { 137, "AFDtek Division of Fastek International Inc." }, { 138, "PowerCold Comfort Air Solutions, Inc." }, { 139, "I Controls" }, { 140, "Viconics Electronics, Inc." }, { 141, "Yaskawa America, Inc." }, { 142, "DEOS control systems GmbH" }, { 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 International Inc." }, { 150, "Advantech Corporation" }, { 151, "Titan Products, Ltd." }, { 152, "Regel Partners" }, { 153, "National Environmental Product" }, { 154, "Unitec Corporation" }, { 155, "Kanden Engineering Company" }, { 156, "Messner Gebäudetechnik GmbH" }, { 157, "Integrated.CH" }, { 158, "Price Industries" }, { 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, "Cooper Controls" }, { 167, "Duksan Mecasys Co., Ltd." }, { 168, "Fuji IT Co., Ltd." }, { 169, "Vacon Plc" }, { 170, "Leader Controls" }, { 171, "ABB (Formerly 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, Inc." }, { 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, "Bosch Building Automation GmbH" }, { 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, "CIMON 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, "Strato Automation" }, { 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, "OpenGeneral Pty., Ltd." }, { 222, "WAGO Kontakttechnik GmbH & Co. KG" }, { 223, "Franklin Electric" }, { 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, "HMS Industrial Networks SLU" }, { 247, "Ingenieurgesellschaft N. Hartleb mbH" }, { 248, "Heat-Timer Corporation" }, { 249, "Ingrasys Technology, Inc." }, { 250, "Costerm Building Automation" }, { 251, "WILO SE" }, { 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, "Exor International 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, "StudioSC" }, { 279, "M-System Co., Ltd." }, { 280, "Yokota Co., Ltd." }, { 281, "Hitranse Technology Co., LTD" }, { 282, "Vigilent Corporation" }, { 283, "Kele, Inc." }, { 284, "BELIMO Automation AG" }, { 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, "FIRVENA s.r.o." }, { 302, "Hitachi Appliances, Inc." }, { 303, "Real Time Automation, Inc." }, { 304, "ITEC Hankyu-Hanshin Co." }, { 305, "Cyrus E&M Engineering Co., Ltd." }, { 306, "Badger Meter" }, { 307, "Cirrascale Corporation" }, { 308, "Elesta GmbH Building Automation" }, { 309, "Securiton" }, { 310, "OSlsoft, Inc." }, { 311, "Hanazeder Electronic GmbH" }, { 312, "Honeywell Security Deutschland, Novar GmbH" }, { 313, "Siemens Industry, 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, "Distech Controls SAS" }, { 333, "Novar/Honeywell" }, { 334, "S4 Integration Solutions" }, { 335, "Schneider Electric" }, { 336, "LHA Systems" }, { 337, "GHM engineering Group, Inc." }, { 338, "Cllimalux S.A." }, { 339, "VAISALA Oyj" }, { 340, "COMPLEX (Beijing) Technology, Co., LTD." }, { 341, "SCADAmetrics" }, { 342, "POWERPEG NSI Limited" }, { 343, "BACnet Interoperability Testing Services, Inc." }, { 344, "Teco a.s." }, { 345, "Plexus Technology, Inc." }, { 346, "Energy Focus, Inc." }, { 347, "Powersmiths International Corp." }, { 348, "Nichibei Co., Ltd." }, { 349, "HKC Technology Ltd." }, { 350, "Ovation Networks, Inc." }, { 351, "Setra Systems" }, { 352, "AVG Automation" }, { 353, "ZXC Ltd." }, { 354, "Byte Sphere" }, { 355, "Generiton Co., Ltd." }, { 356, "Holter Regelarmaturen GmbH & Co. KG" }, { 357, "Bedford Instruments, LLC" }, { 358, "Standair Inc." }, { 359, "WEG Automation – R&D" }, { 360, "Prolon Control Systems ApS" }, { 361, "Inneasoft" }, { 362, "ConneXSoft GmbH" }, { 363, "CEAG Notlichtsysteme GmbH" }, { 364, "Distech Controls Inc." }, { 365, "Industrial Technology Research Institute" }, { 366, "ICONICS, Inc." }, { 367, "IQ Controls s.c." }, { 368, "OJ Electronics A/S" }, { 369, "Rolbit Ltd." }, { 370, "Synapsys Solutions Ltd." }, { 371, "ACME Engineering Prod. Ltd." }, { 372, "Zener Electric Pty, Ltd." }, { 373, "Selectronix, Inc." }, { 374, "Gorbet & Banerjee, LLC." }, { 375, "IME" }, { 376, "Stephen H. Dawson Computer Service" }, { 377, "Accutrol, LLC" }, { 378, "Schneider Elektronik GmbH" }, { 379, "Alpha-Inno Tec GmbH" }, { 380, "ADMMicro, Inc." }, { 381, "Greystone Energy Systems, Inc." }, { 382, "CAP Technologie" }, { 383, "KeRo Systems" }, { 384, "Domat Control System s.r.o." }, { 385, "Efektronics Pty. Ltd." }, { 386, "Hekatron Vertriebs GmbH" }, { 387, "Securiton AG" }, { 388, "Carlo Gavazzi Controls SpA" }, { 389, "Chipkin Automation Systems" }, { 390, "Savant Systems, LLC" }, { 391, "Simmtronic Lighting Controls" }, { 392, "Abelko Innovation AB" }, { 393, "Seresco Technologies Inc." }, { 394, "IT Watchdogs" }, { 395, "Automation Assist Japan Corp." }, { 396, "Thermokon Sensortechnik GmbH" }, { 397, "EGauge Systems, LLC" }, { 398, "Quantum Automation (ASIA) PTE, Ltd." }, { 399, "Toshiba Lighting & Technology Corp." }, { 400, "SPIN Engenharia de Automação Ltda." }, { 401, "Logistics Systems & Software Services India PVT. Ltd." }, { 402, "Delta Controls Integration Products" }, { 403, "Focus Media" }, { 404, "LUMEnergi Inc." }, { 405, "Kara Systems" }, { 406, "RF Code, Inc." }, { 407, "Fatek Automation Corp." }, { 408, "JANDA Software Company, LLC" }, { 409, "Open System Solutions Limited" }, { 410, "Intelec Systems PTY Ltd." }, { 411, "Ecolodgix, LLC" }, { 412, "Douglas Lighting Controls" }, { 413, "iSAtech GmbH" }, { 414, "AREAL" }, { 415, "Beckhoff Automation" }, { 416, "IPAS GmbH" }, { 417, "KE2 Therm Solutions" }, { 418, "Base2Products" }, { 419, "DTL Controls, LLC" }, { 420, "INNCOM International, Inc." }, { 421, "METZ CONNECT GmbH" }, { 422, "Greentrol Automation, Inc" }, { 423, "BELIMO Automation AG" }, { 424, "Samsung Heavy Industries Co, Ltd" }, { 425, "Triacta Power Technologies, Inc." }, { 426, "Globestar Systems" }, { 427, "MLB Advanced Media, LP" }, { 428, "SWG Stuckmann Wirtschaftliche Gebäudesysteme GmbH" }, { 429, "SensorSwitch" }, { 430, "Multitek Power Limited" }, { 431, "Aquametro AG" }, { 432, "LG Electronics Inc." }, { 433, "Electronic Theatre Controls, Inc." }, { 434, "Mitsubishi Electric Corporation Nagoya Works" }, { 435, "Delta Electronics, Inc." }, { 436, "Elma Kurtalj, Ltd." }, { 437, "Tyco Fire & Security GmbH" }, { 438, "Nedap Security Management" }, { 439, "ESC Automation Inc." }, { 440, "DSP4YOU Ltd." }, { 441, "GE Sensing and Inspection Technologies" }, { 442, "Embedded Systems SIA" }, { 443, "BEFEGA GmbH" }, { 444, "Baseline Inc." }, { 445, "Key2Act" }, { 446, "OEMCtrl" }, { 447, "Clarkson Controls Limited" }, { 448, "Rogerwell Control System Limited" }, { 449, "SCL Elements" }, { 450, "Hitachi Ltd." }, { 451, "Newron System SA" }, { 452, "BEVECO Gebouwautomatisering BV" }, { 453, "Streamside Solutions" }, { 454, "Yellowstone Soft" }, { 455, "Oztech Intelligent Systems Pty Ltd." }, { 456, "Novelan GmbH" }, { 457, "Flexim Americas Corporation" }, { 458, "ICP DAS Co., Ltd." }, { 459, "CARMA Industries Inc." }, { 460, "Log-One Ltd." }, { 461, "TECO Electric & Machinery Co., Ltd." }, { 462, "ConnectEx, Inc." }, { 463, "Turbo DDC Südwest" }, { 464, "Quatrosense Environmental Ltd." }, { 465, "Fifth Light Technology Ltd." }, { 466, "Scientific Solutions, Ltd." }, { 467, "Controller Area Network Solutions (M) Sdn Bhd" }, { 468, "RESOL – Elektronische Regelungen GmbH" }, { 469, "RPBUS LLC" }, { 470, "BRS Sistemas Eletronicos" }, { 471, "WindowMaster A/S" }, { 472, "Sunlux Technologies Ltd." }, { 473, "Measurlogic" }, { 474, "Frimat GmbH" }, { 475, "Spirax Sarco" }, { 476, "Luxtron" }, { 477, "Raypak Inc" }, { 478, "Air Monitor Corporation" }, { 479, "Regler Och Webbteknik Sverige (ROWS)" }, { 480, "Intelligent Lighting Controls Inc." }, { 481, "Sanyo Electric Industry Co., Ltd" }, { 482, "E-Mon Energy Monitoring Products" }, { 483, "Digital Control Systems" }, { 484, "ATI Airtest Technologies, Inc." }, { 485, "SCS SA" }, { 486, "HMS Industrial Networks AB" }, { 487, "Shenzhen Universal Intellisys Co Ltd" }, { 488, "EK Intellisys Sdn Bhd" }, { 489, "SysCom" }, { 490, "Firecom, Inc." }, { 491, "ESA Elektroschaltanlagen Grimma GmbH" }, { 492, "Kumahira Co Ltd" }, { 493, "Hotraco" }, { 494, "SABO Elektronik GmbH" }, { 495, "Equip’Trans" }, { 496, "Temperature Control Specialities Co., Inc (TCS)" }, { 497, "FlowCon International A/S" }, { 498, "ThyssenKrupp Elevator Americas" }, { 499, "Abatement Technologies" }, { 500, "Continental Control Systems, LLC" }, { 501, "WISAG Automatisierungstechnik GmbH & Co KG" }, { 502, "EasyIO" }, { 503, "EAP-Electric GmbH" }, { 504, "Hardmeier" }, { 505, "Mircom Group of Companies" }, { 506, "Quest Controls" }, { 507, "Mestek, Inc" }, { 508, "Pulse Energy" }, { 509, "Tachikawa Corporation" }, { 510, "University of Nebraska-Lincoln" }, { 511, "Redwood Systems" }, { 512, "PASStec Industrie-Elektronik GmbH" }, { 513, "NgEK, Inc." }, { 514, "t-mac Technologies" }, { 515, "Jireh Energy Tech Co., Ltd." }, { 516, "Enlighted Inc." }, { 517, "El-Piast Sp. Z o.o" }, { 518, "NetxAutomation Software GmbH" }, { 519, "Invertek Drives" }, { 520, "Deutschmann Automation GmbH & Co. KG" }, { 521, "EMU Electronic AG" }, { 522, "Phaedrus Limited" }, { 523, "Sigmatek GmbH & Co KG" }, { 524, "Marlin Controls" }, { 525, "Circutor, SA" }, { 526, "UTC Fire & Security" }, { 527, "DENT Instruments, Inc." }, { 528, "FHP Manufacturing Company – Bosch Group" }, { 529, "GE Intelligent Platforms" }, { 530, "Inner Range Pty Ltd" }, { 531, "GLAS Energy Technology" }, { 532, "MSR-Electronic-GmbH" }, { 533, "Energy Control Systems, Inc." }, { 534, "EMT Controls" }, { 535, "Daintree" }, { 536, "EURO ICC d.o.o" }, { 537, "TE Connectivity Energy" }, { 538, "GEZE GmbH" }, { 539, "NEC Corporation" }, { 540, "Ho Cheung International Company Limited" }, { 541, "Sharp Manufacturing Systems Corporation" }, { 542, "DOT CONTROLS a.s." }, { 543, "BeaconMedæs" }, { 544, "Midea Commercial Aircon" }, { 545, "WattMaster Controls" }, { 546, "Kamstrup A/S" }, { 547, "CA Computer Automation GmbH" }, { 548, "Laars Heating Systems Company" }, { 549, "Hitachi Systems, Ltd." }, { 550, "Fushan AKE Electronic Engineering Co., Ltd." }, { 551, "Toshiba International Corporation" }, { 552, "Starman Systems, LLC" }, { 553, "Samsung Techwin Co., Ltd." }, { 554, "ISAS-Integrated Switchgear and Systems P/L" }, { 555, "Reserved for ASHRAE" }, { 556, "Obvius" }, { 557, "Marek Guzik" }, { 558, "Vortek Instruments, LLC" }, { 559, "Universal Lighting Technologies" }, { 560, "Myers Power Products, Inc." }, { 561, "Vector Controls GmbH" }, { 562, "Crestron Electronics, Inc." }, { 563, "A&E Controls Limited" }, { 564, "Projektomontaza A.D." }, { 565, "Freeaire Refrigeration" }, { 566, "Aqua Cooler Pty Limited" }, { 567, "Basic Controls" }, { 568, "GE Measurement and Control Solutions Advanced Sensors" }, { 569, "EQUAL Networks" }, { 570, "Millennial Net" }, { 571, "APLI Ltd" }, { 572, "Electro Industries/GaugeTech" }, { 573, "SangMyung University" }, { 574, "Coppertree Analytics, Inc." }, { 575, "CoreNetiX GmbH" }, { 576, "Acutherm" }, { 577, "Dr. Riedel Automatisierungstechnik GmbH" }, { 578, "Shina System Co., Ltd" }, { 579, "Iqapertus" }, { 580, "PSE Technology" }, { 581, "BA Systems" }, { 582, "BTICINO" }, { 583, "Monico, Inc." }, { 584, "iCue" }, { 585, "tekmar Control Systems Ltd." }, { 586, "Control Technology Corporation" }, { 587, "GFAE GmbH" }, { 588, "BeKa Software GmbH" }, { 589, "Isoil Industria SpA" }, { 590, "Home Systems Consulting SpA" }, { 591, "Socomec" }, { 592, "Everex Communications, Inc." }, { 593, "Ceiec Electric Technology" }, { 594, "Atrila GmbH" }, { 595, "WingTechs" }, { 596, "Shenzhen Mek Intellisys Pte Ltd." }, { 597, "Nestfield Co., Ltd." }, { 598, "Swissphone Telecom AG" }, { 599, "PNTECH JSC" }, { 600, "Horner APG, LLC" }, { 601, "PVI Industries, LLC" }, { 602, "Ela-compil" }, { 603, "Pegasus Automation International LLC" }, { 604, "Wight Electronic Services Ltd." }, { 605, "Marcom" }, { 606, "Exhausto A/S" }, { 607, "Dwyer Instruments, Inc." }, { 608, "Link GmbH" }, { 609, "Oppermann Regelgerate GmbH" }, { 610, "NuAire, Inc." }, { 611, "Nortec Humidity, Inc." }, { 612, "Bigwood Systems, Inc." }, { 613, "Enbala Power Networks" }, { 614, "Inter Energy Co., Ltd." }, { 615, "ETC" }, { 616, "COMELEC S.A.R.L" }, { 617, "Pythia Technologies" }, { 618, "TrendPoint Systems, Inc." }, { 619, "AWEX" }, { 620, "Eurevia" }, { 621, "Kongsberg E-lon AS" }, { 622, "FlaktWoods" }, { 623, "E + E Elektronik GES M.B.H." }, { 624, "ARC Informatique" }, { 625, "SKIDATA AG" }, { 626, "WSW Solutions" }, { 627, "Trefon Electronic GmbH" }, { 628, "Dongseo System" }, { 629, "Kanontec Intelligence Technology Co., Ltd." }, { 630, "EVCO S.p.A." }, { 631, "Accuenergy (Canada) Inc." }, { 632, "SoftDEL" }, { 633, "Orion Energy Systems, Inc." }, { 634, "Roboticsware" }, { 635, "DOMIQ Sp. z o.o." }, { 636, "Solidyne" }, { 637, "Elecsys Corporation" }, { 638, "Conditionaire International Pty. Limited" }, { 639, "Quebec, Inc." }, { 640, "Homerun Holdings" }, { 641, "Murata Americas" }, { 642, "Comptek" }, { 643, "Westco Systems, Inc." }, { 644, "Advancis Software & Services GmbH" }, { 645, "Intergrid, LLC" }, { 646, "Markerr Controls, Inc." }, { 647, "Toshiba Elevator and Building Systems Corporation" }, { 648, "Spectrum Controls, Inc." }, { 649, "Mkservice" }, { 650, "Fox Thermal Instruments" }, { 651, "SyxthSense Ltd" }, { 652, "DUHA System S R.O." }, { 653, "NIBE" }, { 654, "Melink Corporation" }, { 655, "Fritz-Haber-Institut" }, { 656, "MTU Onsite Energy GmbH, Gas Power Systems" }, { 657, "Omega Engineering, Inc." }, { 658, "Avelon" }, { 659, "Ywire Technologies, Inc." }, { 660, "M.R. Engineering Co., Ltd." }, { 661, "Lochinvar, LLC" }, { 662, "Sontay Limited" }, { 663, "GRUPA Slawomir Chelminski" }, { 664, "Arch Meter Corporation" }, { 665, "Senva, Inc." }, { 666, "Reserved for ASHRAE" }, { 667, "FM-Tec" }, { 668, "Systems Specialists, Inc." }, { 669, "SenseAir" }, { 670, "AB IndustrieTechnik Srl" }, { 671, "Cortland Research, LLC" }, { 672, "MediaView" }, { 673, "VDA Elettronica" }, { 674, "CSS, Inc." }, { 675, "Tek-Air Systems, Inc." }, { 676, "ICDT" }, { 677, "The Armstrong Monitoring Corporation" }, { 678, "DIXELL S.r.l" }, { 679, "Lead System, Inc." }, { 680, "ISM EuroCenter S.A." }, { 681, "TDIS" }, { 682, "Trade FIDES" }, { 683, "Knürr GmbH (Emerson Network Power)" }, { 684, "Resource Data Management" }, { 685, "Abies Technology, Inc." }, { 686, "UAB Komfovent" }, { 687, "MIRAE Electrical Mfg. Co., Ltd." }, { 688, "HunterDouglas Architectural Projects Scandinavia ApS" }, { 689, "RUNPAQ Group Co., Ltd" }, { 690, "Unicard SA" }, { 691, "IE Technologies" }, { 692, "Ruskin Manufacturing" }, { 693, "Calon Associates Limited" }, { 694, "Contec Co., Ltd." }, { 695, "iT GmbH" }, { 696, "Autani Corporation" }, { 697, "Christian Fortin" }, { 698, "HDL" }, { 699, "IPID Sp. Z.O.O Limited" }, { 700, "Fuji Electric Co., Ltd" }, { 701, "View, Inc." }, { 702, "Samsung S1 Corporation" }, { 703, "New Lift" }, { 704, "VRT Systems" }, { 705, "Motion Control Engineering, Inc." }, { 706, "Weiss Klimatechnik GmbH" }, { 707, "Elkon" }, { 708, "Eliwell Controls S.r.l." }, { 709, "Japan Computer Technos Corp" }, { 710, "Rational Network ehf" }, { 711, "Magnum Energy Solutions, LLC" }, { 712, "MelRok" }, { 713, "VAE Group" }, { 714, "LGCNS" }, { 715, "Berghof Automationstechnik GmbH" }, { 716, "Quark Communications, Inc." }, { 717, "Sontex" }, { 718, "mivune AG" }, { 719, "Panduit" }, { 720, "Smart Controls, LLC" }, { 721, "Compu-Aire, Inc." }, { 722, "Sierra" }, { 723, "ProtoSense Technologies" }, { 724, "Eltrac Technologies Pvt Ltd" }, { 725, "Bektas Invisible Controls GmbH" }, { 726, "Entelec" }, { 727, "INNEXIV" }, { 728, "Covenant" }, { 729, "Davitor AB" }, { 730, "TongFang Technovator" }, { 731, "Building Robotics, Inc." }, { 732, "HSS-MSR UG" }, { 733, "FramTack LLC" }, { 734, "B. L. Acoustics, Ltd." }, { 735, "Traxxon Rock Drills, Ltd" }, { 736, "Franke" }, { 737, "Wurm GmbH & Co" }, { 738, "AddENERGIE" }, { 739, "Mirle Automation Corporation" }, { 740, "Ibis Networks" }, { 741, "ID-KARTA s.r.o." }, { 742, "Anaren, Inc." }, { 743, "Span, Incorporated" }, { 744, "Bosch Thermotechnology Corp" }, { 745, "DRC Technology S.A." }, { 746, "Shanghai Energy Building Technology Co, Ltd" }, { 747, "Fraport AG" }, { 748, "Flowgroup" }, { 749, "Skytron Energy, GmbH" }, { 750, "ALTEL Wicha, Golda Sp. J." }, { 751, "Drupal" }, { 752, "Axiomatic Technology, Ltd" }, { 753, "Bohnke + Partner" }, { 754, "Function1" }, { 755, "Optergy Pty, Ltd" }, { 756, "LSI Virticus" }, { 757, "Konzeptpark GmbH" }, { 758, "NX Lighting Controls" }, { 759, "eCurv, Inc." }, { 760, "Agnosys GmbH" }, { 761, "Shanghai Sunfull Automation Co., LTD" }, { 762, "Kurz Instruments, Inc." }, { 763, "Cias Elettronica S.r.l." }, { 764, "Multiaqua, Inc." }, { 765, "BlueBox" }, { 766, "Sensidyne" }, { 767, "Viessmann Elektronik GmbH" }, { 768, "ADFweb.com srl" }, { 769, "Gaylord Industries" }, { 770, "Majur Ltd." }, { 771, "Shanghai Huilin Technology Co., Ltd." }, { 772, "Exotronic" }, { 773, "SAFECONTROL s.r.o." }, { 774, "Amatis" }, { 775, "Universal Electric Corporation" }, { 776, "iBACnet" }, { 777, "Reserved for ASHRAE" }, { 778, "Smartrise Engineering, Inc." }, { 779, "Miratron, Inc." }, { 780, "SmartEdge" }, { 781, "Mitsubishi Electric Australia Pty Ltd" }, { 782, "Triangle Research International Ptd Ltd" }, { 783, "Produal Oy" }, { 784, "Milestone Systems A/S" }, { 785, "Trustbridge" }, { 786, "Feedback Solutions" }, { 787, "IES" }, { 788, "ABB Power Protection SA" }, { 789, "Riptide IO" }, { 790, "Messerschmitt Systems AG" }, { 791, "Dezem Energy Controlling" }, { 792, "MechoSystems" }, { 793, "evon GmbH" }, { 794, "CS Lab GmbH" }, { 795, "8760 Enterprises, Inc." }, { 796, "Touche Controls" }, { 797, "Ontrol Teknik Malzeme San. ve Tic. A.S." }, { 798, "Uni Control System Sp. Z o.o." }, { 799, "Weihai Ploumeter Co., Ltd" }, { 800, "Elcom International Pvt. Ltd" }, { 801, "Signify" }, { 802, "AutomationDirect" }, { 803, "Paragon Robotics" }, { 804, "SMT System & Modules Technology AG" }, { 805, "Radix IoT LLC" }, { 806, "CMR Controls Ltd" }, { 807, "Innovari, Inc." }, { 808, "ABB Control Products" }, { 809, "Gesellschaft fur Gebäudeautomation mbH" }, { 810, "RODI Systems Corp." }, { 811, "Nextek Power Systems" }, { 812, "Creative Lighting" }, { 813, "WaterFurnace International" }, { 814, "Mercury Security" }, { 815, "Hisense (Shandong) Air-Conditioning Co., Ltd." }, { 816, "Layered Solutions, Inc." }, { 817, "Leegood Automatic System, Inc." }, { 818, "Shanghai Restar Technology Co., Ltd." }, { 819, "Reimann Ingenieurbüro" }, { 820, "LynTec" }, { 821, "HTP" }, { 822, "Elkor Technologies, Inc." }, { 823, "Bentrol Pty Ltd" }, { 824, "Team-Control Oy" }, { 825, "NextDevice, LLC" }, { 826, "iSMA CONTROLLI S.p.a." }, { 827, "King I Electronics Co., Ltd" }, { 828, "SAMDAV" }, { 829, "Next Gen Industries Pvt. Ltd." }, { 830, "Entic LLC" }, { 831, "ETAP" }, { 832, "Moralle Electronics Limited" }, { 833, "Leicom AG" }, { 834, "Watts Regulator Company" }, { 835, "S.C. Orbtronics S.R.L." }, { 836, "Gaussan Technologies" }, { 837, "WEBfactory GmbH" }, { 838, "Ocean Controls" }, { 839, "Messana Air-Ray Conditioning s.r.l." }, { 840, "Hangzhou BATOWN Technology Co. Ltd." }, { 841, "Reasonable Controls" }, { 842, "Servisys, Inc." }, { 843, "halstrup-walcher GmbH" }, { 844, "SWG Automation Fuzhou Limited" }, { 845, "KSB Aktiengesellschaft" }, { 846, "Hybryd Sp. z o.o." }, { 847, "Helvatron AG" }, { 848, "Oderon Sp. Z.O.O." }, { 849, "mikolab" }, { 850, "Exodraft" }, { 851, "Hochhuth GmbH" }, { 852, "Integrated System Technologies Ltd." }, { 853, "Shanghai Cellcons Controls Co., Ltd" }, { 854, "Emme Controls, LLC" }, { 855, "Field Diagnostic Services, Inc." }, { 856, "Ges Teknik A.S." }, { 857, "Global Power Products, Inc." }, { 858, "Option NV" }, { 859, "BV-Control AG" }, { 860, "Sigren Engineering AG" }, { 861, "Shanghai Jaltone Technology Co., Ltd." }, { 862, "MaxLine Solutions Ltd" }, { 863, "Kron Instrumentos Elétricos Ltda" }, { 864, "Thermo Matrix" }, { 865, "Infinite Automation Systems, Inc." }, { 866, "Vantage" }, { 867, "Elecon Measurements Pvt Ltd" }, { 868, "TBA" }, { 869, "Carnes Company" }, { 870, "Harman Professional" }, { 871, "Nenutec Asia Pacific Pte Ltd" }, { 872, "Gia NV" }, { 873, "Kepware Tehnologies" }, { 874, "Temperature Electronics Ltd" }, { 875, "Packet Power" }, { 876, "Project Haystack Corporation" }, { 877, "DEOS Controls Americas Inc." }, { 878, "Senseware Inc" }, { 879, "MST Systemtechnik AG" }, { 880, "Lonix Ltd" }, { 881, "Gossen Metrawatt GmbH" }, { 882, "Aviosys International Inc." }, { 883, "Efficient Building Automation Corp." }, { 884, "Accutron Instruments Inc." }, { 885, "Vermont Energy Control Systems LLC" }, { 886, "DCC Dynamics" }, { 887, "B.E.G. Brück Electronic GmbH" }, { 888, "Reserved for ASHRAE" }, { 889, "NGBS Hungary Ltd." }, { 890, "ILLUM Technology, LLC" }, { 891, "Delta Controls Germany Limited" }, { 892, "S+T Service & Technique S.A." }, { 893, "SimpleSoft" }, { 894, "Altair Engineering" }, { 895, "EZEN Solution Inc." }, { 896, "Fujitec Co. Ltd." }, { 897, "Terralux" }, { 898, "Annicom" }, { 899, "Bihl+Wiedemann GmbH" }, { 900, "Draper, Inc." }, { 901, "Schüco International KG" }, { 902, "Otis Elevator Company" }, { 903, "Fidelix Oy" }, { 904, "RAM GmbH Mess- und Regeltechnik" }, { 905, "WEMS" }, { 906, "Ravel Electronics Pvt Ltd" }, { 907, "OmniMagni" }, { 908, "Echelon" }, { 909, "Intellimeter Canada, Inc." }, { 910, "Bithouse Oy" }, { 911, "Reserved for ASHRAE" }, { 912, "BuildPulse" }, { 913, "Shenzhen 1000 Building Automation Co. Ltd" }, { 914, "AED Engineering GmbH" }, { 915, "Güntner GmbH & Co. KG" }, { 916, "KNXlogic" }, { 917, "CIM Environmental Group" }, { 918, "Flow Control" }, { 919, "Lumen Cache, Inc." }, { 920, "Ecosystem" }, { 921, "Potter Electric Signal Company, LLC" }, { 922, "Tyco Fire & Security S.p.A." }, { 923, "Watanabe Electric Industry Co., Ltd." }, { 924, "Causam Energy" }, { 925, "W-tec AG" }, { 926, "IMI Hydronic Engineering International SA" }, { 927, "ARIGO Software" }, { 928, "MSA Safety" }, { 929, "Smart Solucoes Ltda – MERCATO" }, { 930, "PIATRA Engineering" }, { 931, "ODIN Automation Systems, LLC" }, { 932, "Belparts NV" }, { 933, "UAB, SALDA" }, { 934, "Alre-IT Regeltechnik GmbH" }, { 935, "Ingenieurbüro H. Lertes GmbH & Co. KG" }, { 936, "Breathing Buildings" }, { 937, "eWON SA" }, { 938, "Cav. Uff. Giacomo Cimberio S.p.A" }, { 939, "PKE Electronics AG" }, { 940, "Allen" }, { 941, "Kastle Systems" }, { 942, "Logical Electro-Mechanical (EM) Systems, Inc." }, { 943, "ppKinetics Instruments, LLC" }, { 944, "Cathexis Technologies" }, { 945, "Sylop sp. Z o.o. sp.k" }, { 946, "Brauns Control GmbH" }, { 947, "OMRON SOCIAL SOLUTIONS CO., LTD." }, { 948, "Wildeboer Bauteile Gmbh" }, { 949, "Shanghai Biens Technologies Ltd" }, { 950, "Beijing HZHY Technology Co., Ltd" }, { 951, "Building Clouds" }, { 952, "The University of Sheffield-Department of Electronic and Electrical Engineering" }, { 953, "Fabtronics Australia Pty Ltd" }, { 954, "SLAT" }, { 955, "Software Motor Corporation" }, { 956, "Armstrong International Inc." }, { 957, "Steril-Aire, Inc." }, { 958, "Infinique" }, { 959, "Arcom" }, { 960, "Argo Performance, Ltd" }, { 961, "Dialight" }, { 962, "Ideal Technical Solutions" }, { 963, "Neurobat AG" }, { 964, "Neyer Software Consulting LLC" }, { 965, "SCADA Technology Development Co., Ltd." }, { 966, "Demand Logic Limited" }, { 967, "GWA Group Limited" }, { 968, "Occitaline" }, { 969, "NAO Digital Co., Ltd." }, { 970, "Shenzhen Chanslink Network Technology Co., Ltd." }, { 971, "Samsung Electronics Co., Ltd." }, { 972, "Mesa Laboratories, Inc." }, { 973, "Fischer" }, { 974, "OpSys Solutions Ltd." }, { 975, "Advanced Devices Limited" }, { 976, "Condair" }, { 977, "INELCOM Ingenieria Electronica Comercial S.A." }, { 978, "GridPoint, Inc." }, { 979, "ADF Technologies Sdn Bhd" }, { 980, "EPM, Inc." }, { 981, "Lighting Controls Ltd" }, { 982, "Perix Controls Ltd." }, { 983, "AERCO International, Inc." }, { 984, "KONE Inc." }, { 985, "Ziehl-Abegg SE" }, { 986, "Robot, S.A." }, { 987, "Optigo Networks, Inc." }, { 988, "Openmotics BVBA" }, { 989, "Metropolitan Industries, Inc." }, { 990, "Huawei Technologies Co., Ltd." }, { 991, "Digital Lumens, Inc." }, { 992, "Vanti" }, { 993, "Cree Lighting" }, { 994, "Richmond Heights SDN BHD" }, { 995, "Payne-Sparkman Lighting Mangement" }, { 996, "Ashcroft" }, { 997, "Jet Controls Corp" }, { 998, "Zumtobel Lighting GmbH" }, { 999, "Reserved for ASHRAE" }, { 1000, "Ekon GmbH" }, { 1001, "Molex" }, { 1002, "Maco Lighting Pty Ltd." }, { 1003, "Axecon Corp." }, { 1004, "Tensor plc" }, { 1005, "Kaseman Environmental Control Equipment (Shanghai) Limited" }, { 1006, "AB Axis Industries" }, { 1007, "Netix Controls" }, { 1008, "Eldridge Products, Inc." }, { 1009, "Micronics" }, { 1010, "Fortecho Solutions Ltd" }, { 1011, "Sellers Manufacturing Company" }, { 1012, "Rite-Hite Doors, Inc." }, { 1013, "Violet Defense LLC" }, { 1014, "Simna" }, { 1015, "Multi-Énergie Best Inc." }, { 1016, "Mega System Technologies, Inc." }, { 1017, "Rheem" }, { 1018, "Ing. Punzenberger COPA-DATA GmbH" }, { 1019, "MEC Electronics GmbH" }, { 1020, "Taco Comfort Solutions" }, { 1021, "Alexander Maier GmbH" }, { 1022, "Ecorithm, Inc." }, { 1023, "Accurro Ltd" }, { 1024, "ROMTECK Australia Pty Ltd" }, { 1025, "Splash Monitoring Limited" }, { 1026, "Light Application" }, { 1027, "Logical Building Automation" }, { 1028, "Exilight Oy" }, { 1029, "Hager Electro SAS" }, { 1030, "KLIF Co., LTD" }, { 1031, "HygroMatik" }, { 1032, "Daniel Mousseau Programmation & Electronique" }, { 1033, "Aerionics Inc." }, { 1034, "M2S Electronique Ltee" }, { 1035, "Automation Components, Inc." }, { 1036, "Niobrara Research & Development Corporation" }, { 1037, "Netcom Sicherheitstechnik GmbH" }, { 1038, "Lumel S.A." }, { 1039, "Great Plains Industries, Inc." }, { 1040, "Domotica Labs S.R.L" }, { 1041, "Energy Cloud, Inc." }, { 1042, "Vomatec" }, { 1043, "Demma Companies" }, { 1044, "Valsena" }, { 1045, "Comsys Bärtsch AG" }, { 1046, "bGrid" }, { 1047, "MDJ Software Pty Ltd" }, { 1048, "Dimonoff, Inc." }, { 1049, "Edomo Systems, GmbH" }, { 1050, "Effektiv, LLC" }, { 1051, "SteamOVap" }, { 1052, "grandcentrix GmbH" }, { 1053, "Weintek Labs, Inc." }, { 1054, "Intefox GmbH" }, { 1055, "Radius22 Automation Company" }, { 1056, "Ringdale, Inc." }, { 1057, "Iwaki America" }, { 1058, "Bractlet" }, { 1059, "STULZ Air Technology Systems, Inc." }, { 1060, "Climate Ready Engineering Pty Ltd" }, { 1061, "Genea Energy Partners" }, { 1062, "IoTall Chile" }, { 1063, "IKS Co., Ltd." }, { 1064, "Yodiwo AB" }, { 1065, "TITAN electronic GmbH" }, { 1066, "IDEC Corporation" }, { 1067, "SIFRI SL" }, { 1068, "Thermal Gas Systems Inc." }, { 1069, "Building Automation Products, Inc." }, { 1070, "Asset Mapping" }, { 1071, "Smarteh Company" }, { 1072, "Datapod (Australia) Pty Ltd." }, { 1073, "Buildings Alive Pty Ltd" }, { 1074, "Digital Elektronik" }, { 1075, "Talent Automação e Tecnologia Ltda" }, { 1076, "Norposh Limited" }, { 1077, "Merkur Funksysteme AG" }, { 1078, "Faster CZ spol. S.r.o" }, { 1079, "Eco-Adapt" }, { 1080, "Energocentrum Plus, s.r.o" }, { 1081, "amBX UK Ltd" }, { 1082, "Western Reserve Controls, Inc." }, { 1083, "LayerZero Power Systems, Inc." }, { 1084, "CIC Jan Hřebec s.r.o." }, { 1085, "Sigrov BV" }, { 1086, "ISYS-Intelligent Systems" }, { 1087, "Gas Detection (Australia) Pty Ltd" }, { 1088, "Kinco Automation (Shanghai) Ltd." }, { 1089, "Lars Energy, LLC" }, { 1090, "Flamefast (UK) Ltd." }, { 1091, "Royal Service Air Conditioning" }, { 1092, "Ampio Sp. Z o.o." }, { 1093, "Inovonics Wireless Corporation" }, { 1094, "Nvent Thermal Management" }, { 1095, "Sinowell Control System Ltd" }, { 1096, "Moxa Inc." }, { 1097, "Matrix iControl SDN BHD" }, { 1098, "PurpleSwift" }, { 1099, "OTIM Technologies" }, { 1100, "FlowMate Limited" }, { 1101, "Degree Controls, Inc." }, { 1102, "Fei Xing (Shanghai) Software Technologies Co., Ltd." }, { 1103, "Berg GmbH" }, { 1104, "ARENZ.IT" }, { 1105, "Edelstrom Electronic Devices & Designing LLC" }, { 1106, "Drive Connect, LLC" }, { 1107, "DevelopNow" }, { 1108, "Poort" }, { 1109, "VMEIL Information (Shanghai) Ltd" }, { 1110, "Rayleigh Instruments" }, { 1111, "Reserved for ASHRAE" }, { 1112, "CODESYS Development" }, { 1113, "Smartware Technologies Group, LLC" }, { 1114, "Polar Bear Solutions" }, { 1115, "Codra" }, { 1116, "Pharos Architectural Controls Ltd" }, { 1117, "EngiNear Ltd." }, { 1118, "Ad Hoc Electronics" }, { 1119, "Unified Microsystems" }, { 1120, "Industrieelektronik Brandenburg GmbH" }, { 1121, "Hartmann GmbH" }, { 1122, "Piscada" }, { 1123, "KMB systems, s.r.o." }, { 1124, "PowerTech Engineering AS" }, { 1125, "Telefonbau Arthur Schwabe GmbH & Co. KG" }, { 1126, "Wuxi Fistwelove Technology Co., Ltd." }, { 1127, "Prysm" }, { 1128, "STEINEL GmbH" }, { 1129, "Georg Fischer JRG AG" }, { 1130, "Make Develop SL" }, { 1131, "Monnit Corporation" }, { 1132, "Mirror Life Corporation" }, { 1133, "Secure Meters Limited" }, { 1134, "PECO" }, { 1135, ".CCTECH, Inc." }, { 1136, "LightFi Limited" }, { 1137, "Nice Spa" }, { 1138, "Fiber SenSys, Inc." }, { 1139, "B&D Buchta und Degeorgi" }, { 1140, "Ventacity Systems, Inc." }, { 1141, "Hitachi-Johnson Controls Air Conditioning, Inc." }, { 1142, "Sage Metering, Inc." }, { 1143, "Andel Limited" }, { 1144, "ECOSmart Technologies" }, { 1145, "S.E.T." }, { 1146, "Protec Fire Detection Spain SL" }, { 1147, "AGRAMER UG" }, { 1148, "Anylink Electronic GmbH" }, { 1149, "Schindler, Ltd" }, { 1150, "Jibreel Abdeen Est." }, { 1151, "Fluidyne Control Systems Pvt. Ltd" }, { 1152, "Prism Systems, Inc." }, { 1153, "Enertiv" }, { 1154, "Mirasoft GmbH & Co. KG" }, { 1155, "DUALTECH IT" }, { 1156, "Countlogic, LLC" }, { 1157, "Kohler" }, { 1158, "Chen Sen Controls Co., Ltd." }, { 1159, "Greenheck" }, { 1160, "Intwine Connect, LLC" }, { 1161, "Karlborgs Elkontroll" }, { 1162, "Datakom" }, { 1163, "Hoga Control AS" }, { 1164, "Cool Automation" }, { 1165, "Inter Search Co., Ltd" }, { 1166, "DABBEL-Automation Intelligence GmbH" }, { 1167, "Gadgeon Engineering Smartness" }, { 1168, "Coster Group S.r.l." }, { 1169, "Walter Müller AG" }, { 1170, "Fluke" }, { 1171, "Quintex Systems Ltd" }, { 1172, "Senfficient SDN BHD" }, { 1173, "Nube iO Operations Pty Ltd" }, { 1174, "DAS Integrator Pte Ltd" }, { 1175, "CREVIS Co., Ltd" }, { 1176, "iSquared software inc." }, { 1177, "KTG GmbH" }, { 1178, "POK Group Oy" }, { 1179, "Adiscom" }, { 1180, "Incusense" }, { 1181, "75F" }, { 1182, "Anord Mardix, Inc." }, { 1183, "HOSCH Gebäudeautomation Neue Produkte GmbH" }, { 1184, "Bosch.IO GmbH" }, { 1185, "Royal Boon Edam International B.V." }, { 1186, "Clack Corporation" }, { 1187, "Unitex Controls LLC" }, { 1188, "KTC Göteborg AB" }, { 1189, "Interzon AB" }, { 1190, "ISDE ING SL" }, { 1191, "ABM automation building messaging GmbH" }, { 1192, "Kentec Electronics Ltd" }, { 1193, "Emerson Commercial and Residential Solutions" }, { 1194, "Powerside" }, { 1195, "SMC Group" }, { 1196, "EOS Weather Instruments" }, { 1197, "Zonex Systems" }, { 1198, "Generex Systems Computervertriebsgesellschaft mbH" }, { 1199, "Energy Wall LLC" }, { 1200, "Thermofin" }, { 1201, "SDATAWAY SA" }, { 1202, "Biddle Air Systems Limited" }, { 1203, "Kessler Ellis Products" }, { 1204, "Thermoscreens" }, { 1205, "Modio" }, { 1206, "Newron Solutions" }, { 1207, "Unitronics" }, { 1208, "TRILUX GmbH & Co. KG" }, { 1209, "Kollmorgen Steuerungstechnik GmbH" }, { 1210, "Bosch Rexroth AG" }, { 1211, "Alarko Carrier" }, { 1212, "Verdigris Technologies" }, { 1213, "Shanghai SIIC-Longchuang Smartech So., Ltd." }, { 1214, "Quinda Co." }, { 1215, "GRUNER AG" }, { 1216, "BACMOVE" }, { 1217, "PSIDAC AB" }, { 1218, "ISICON-Control Automation" }, { 1219, "Big Ass Fans" }, { 1220, "din – Dietmar Nocker Facility Management GmbH" }, { 1221, "Teldio" }, { 1222, "MIKROKLIMA s.r.o." }, { 1223, "Density" }, { 1224, "ICONAG-Leittechnik GmbH" }, { 1225, "Awair" }, { 1226, "T&D Engineering, Ltd" }, { 1227, "Sistemas Digitales" }, { 1228, "Loxone Electronics GmbH" }, { 1229, "ActronAir" }, { 1230, "Inductive Automation" }, { 1231, "Thor Engineering GmbH" }, { 1232, "Berner International, LLC" }, { 1233, "Potsdam Sensors LLC" }, { 1234, "Kohler Mira Ltd" }, { 1235, "Tecomon GmbH" }, { 1236, "Two Dimensional Instruments, LLC" }, { 1237, "LEFA Technologies Pte. Ltd." }, { 1238, "EATON CEAG Notlichtsysteme GmbH" }, { 1239, "Commbox Tecnologia" }, { 1240, "IPVideo Corporation" }, { 1241, "Bender GmbH & Co. KG" }, { 1242, "Rhymebus Corporation" }, { 1243, "Axon Systems Ltd" }, { 1244, "Engineered Air" }, { 1245, "Elipse Software Ltda" }, { 1246, "Simatix Building Technologies Pvt. Ltd." }, { 1247, "W.A. Benjamin Electric Co." }, { 1248, "TROX Air Conditioning Components (Suzhou) Co. Ltd." }, { 1249, "SC Medical Pty Ltd." }, { 1250, "Elcanic A/S" }, { 1251, "Obeo AS" }, { 1252, "Tapa, Inc." }, { 1253, "ASE Smart Energy, Inc." }, { 1254, "Performance Services, Inc." }, { 1255, "Veridify Security" }, { 1256, "CD Innovation LTD" }, { 1257, "Ben Peoples Industries, LLC" }, { 1258, "UNICOMM Sp. z o.o" }, { 1259, "Thing Technologies GmbH" }, { 1260, "Beijing Hailin Control Technology, Inc." }, { 1261, "Digital Realty" }, { 1262, "Agrowtek Inc." }, { 1263, "DSP Innovation BV" }, { 1264, "STV Electronic GmbH" }, { 1265, "Elmeasure India Pvt Ltd." }, { 1266, "Pineshore Energy LLC" }, { 1267, "Brasch Environmental Technologies, LLC" }, { 1268, "Lion Controls Co., LTD" }, { 1269, "Sinux" }, { 1270, "Avnet Inc." }, { 1271, "Somfy Activites SA" }, { 1272, "Amico" }, { 1273, "SageGlass" }, { 1274, "AuVerte" }, { 1275, "Agile Connects Pvt. Ltd." }, { 1276, "Locimation Pty Ltd" }, { 1277, "Envio Systems GmbH" }, { 1278, "Voytech Systems Limited" }, { 1279, "Davidsmeyer und Paul GmbH" }, { 1280, "Lusher Engineering Services" }, { 1281, "CHNT Nanjing Techsel Intelligent Company LTD" }, { 1282, "Threetronics Pty Ltd" }, { 1283, "SkyFoundry, LLC" }, { 1284, "HanilProTech" }, { 1285, "Sensorscall" }, { 1286, "Shanghai Jingpu Information Technology, Co., Ltd." }, { 1287, "Lichtmanufaktur Berlin GmbH" }, { 1288, "Eco Parking Technologies" }, { 1289, "Envision Digital International Pte Ltd" }, { 1290, "Antony Developpement Electronique" }, { 1291, "i2systems" }, { 1292, "Thureon International Limited" }, { 1293, "Pulsafeeder" }, { 1294, "MegaChips Corporation" }, { 1295, "TES Controls" }, { 1296, "Cermate" }, { 1297, "Grand Valley State University" }, { 1298, "Symcon Gmbh" }, { 1299, "The Chicago Faucet Company" }, { 1300, "Geberit AG" }, { 1301, "Rex Controls" }, { 1302, "IVMS GmbH" }, { 1303, "MNPP Saturn Ltd." }, { 1304, "Regal Beloit" }, { 1305, "ACS-Air Conditioning Solutions" }, { 1306, "GBX Technology, LLC" }, { 1307, "Kaiterra" }, { 1308, "ThinKuan loT Technology (Shanghai) Co., Ltd" }, { 1309, "HoCoSto B.V." }, { 1310, "Shenzhen AS-AI Technology Co., Ltd." }, { 1311, "RPS S.p.a." }, { 1312, "Esmé solutions" }, { 1313, "IOTech Systems Limited" }, { 1314, "i-AutoLogic Co., Ltd." }, { 1315, "New Age Micro, LLC" }, { 1316, "Guardian Glass" }, { 1317, "Guangzhou Zhaoyu Information Technology" }, { 1318, "ACE IoT Solutions LLC" }, { 1319, "Poris Electronics Co., Ltd." }, { 1320, "Terminus Technologies Group" }, { 1321, "Intech 21, Inc." }, { 1322, "Accurate Electronics" }, { 1323, "Fluence Bioengineering" }, { 1324, "Mun Hean Singapore Pte Ltd" }, { 1325, "Katronic AG & Co. KG" }, { 1326, "Suzhou XinAo Information Technology Co. Ltd" }, { 1327, "Linktekk Technology, JSC." }, { 1328, "Stirling Ultracold" }, { 1329, "UV Partners, Inc." }, { 1330, "ProMinent GmbH" }, { 1331, "Multi-Tech Systems, Inc." }, { 1332, "JUMO GmbH & Co. KG" }, { 1333, "Qingdao Huarui Technology Co. Ltd.," }, { 1334, "Cairn Systemes" }, { 1335, "NeuroLogic Research Corp." }, { 1336, "Transition Technologies Advanced Solutions Sp. z o.o" }, { 1337, "Xxter bv" }, { 1338, "PassiveLogic" }, { 1339, "EnSmart Controls" }, { 1340, "Watts Heating and Hot Water Solutions, dba Lync" }, { 1341, "Troposphaira Technologies LLP" }, { 1342, "Network Thermostat" }, { 1343, "Titanium Intelligent Solutions, LLC" }, { 1344, "Numa Products, LLC" }, { 1345, "WAREMA Renkhoff SE" }, { 1346, "Frese A/S" }, { 1347, "Mapped" }, { 1348, "ELEKTRODESIGN ventilatory s.r.o" }, { 1349, "AirCare Automation, Inc." }, { 1350, "Antrum" }, { 1351, "Bao Linh Connect Technology" }, { 1352, "Virginia Controls, LLC" }, { 1353, "Duosys SDN BHD" }, { 1354, "Onsen SAS" }, { 1355, "Vaughn Thermal Corporation" }, { 1356, "Thermoplastic Engineering Ltd (TPE)" }, { 1357, "Wirth Research Ltd." }, { 1358, "SST Automation" }, { 1359, "Shanghai Bencol Electronic Technology Co., Ltd" }, { 1360, "AIWAA Systems Private Limited" }, { 1361, "Enless Wireless" }, { 1362, "Ozuno Engineering Pty Ltd" }, { 1363, "Hubbell, The Electric Heater Company" }, { 1364, "Industrial Turnaround Corporation (ITAC)" }, { 1365, "Wadsworth Control Systems" }, { 1366, "Services Hilo Inc." }, { 1367, "iDM Energiesysteme GmbH" }, { 1368, "BeNext B.V." }, { 1369, "CleanAir.ai Corporation" }, { 1369, "CleanAir.ai Corporation" }, { 1370, "Revolution Microelectronics (America) Inc." }, { 1371, "Real-Time Systems GmbH" }, { 1372, "ZedBee Technologies Pvt Ltd" }, { 1373, "Winmate Technology Solutions Pvt. Ltd." }, { 1373, "Winmate Technology Solutions Pvt. Ltd." }, { 1374, "Senticon Ltd." }, { 1375, "Rossaker AB" }, { 1376, "OPIT Solutions Ltd" }, { 1377, "Hotowell International Co., Limited" }, { 1378, "Inim Electronics S.R.L. Unipersonale" }, { 1379, "Airthings ASA" }, { 1380, "Analog Devices, Inc." }, { 1381, "AIDirections DMCC" }, { 1382, "Prima Electro S.p.A." }, { 1383, "KLT Control System Ltd." }, { 1384, "Evolution Controls Inc." }, { 1385, "Bever Innovations" }, { 1386, "Pelican Wireless Systems" }, { 1387, "Control Concepts Inc." }, { 1388, "Augmatic Technologies Pvt. Ltd." }, { 1389, "Xiamen Milesight loT Co., Ltd" }, { 1390, "Tianjin Anjie loT Schience and Technology Co., Ltd" }, { 1391, "Guangzhou S. Energy Electronics Technology Co. Ltd." }, { 1392, "AKVO Atmospheric Water Systems Pvt. Ltd." }, { 1393, "EmFirst Co. Ltd." }, { 1394, "Iion Systems ApS" }, { 1396, "SAF Tehnika JSC" }, { 1397, "Komfort IQ, Inc." }, { 1398, "CoolTera Limited" }, { 1399, "Hadron Solutions S.r.l.s" }, { 1401, "Bitpool" }, { 1402, "Sonicu, LLC" }, { 1403, "Rishabh Instruments Limited" }, { 1404, "Thing Warehouse LLC" }, { 1405, "Innofriends GmbH" }, { 1406, "Metronic AKP Sp. J." }, { 1407, "Techknave" }, { 1408, "Elsner Elektronik" }, { 1409, "LEFOO Industrial (Hangzhou) Co., Ltd." }, { 1410, "Calibration Technologies, Inc." }, { 1411, "Allorado" }, { 1412, "Verkada" }, { 1413, "Wattsense" }, { 1414, "Emerson Automation Solutions" }, { 1415, "Growlink" }, { 1416, "Olympia Electronics" }, { 1417, "Normal Software, Inc." }, { 1418, "ST Engineering Solution JSC" }, { 1419, "Industrial Flow Solutions" }, { 1420, "Ubiqisense ApS" }, { 1421, "Tiger-Soft" }, { 1422, "Ecodom Srl" }, { 1423, "Bilgipro IoT Systems" }, { 1424, "planspur netdesign GmbH" }, { 1425, "Dolphin Solutions Ltd" }, { 1426, "Mitsubishi Electric Corporation, Kobe Works" }, { 1427, "Ecovena" }, { 1428, "Gree Electric Appliances Inc of Zhuhai" }, { 1429, "Conspec Controls" }, { 1430, "Hangzhou Hikvision Digital Technology Co., Ltd." }, { 1431, "Crystal Peak Security" }, { 1432, "PermAlert" }, { 1433, "Zhejiang Misilin Technology Co., Ltd." }, { 1434, "Dekker Vacuum Technologies" }, { 1435, "Edwards Limited" }, { 1436, "Leybold GmbH" }, { 1437, "International Gas Detectors" }, { 1438, "Atlas Copco Airpower NV" }, { 1439, "Air Sentry Limited" }, { 1440, "Aelsys" }, { 1441, "Granby Consulting LLC" }, { 1442, "Clever Relay" }, { 1443, "Monico Monitoring, Inc." }, { 1444, "Oqdo" }, { 1445, "Matrix Comsec Private Limited" }, { 1446, "Resource Solutions" }, { 1447, "American Gas Safety, LLC" }, { 1448, "S&S Northern Ltd." }, { 1449, "Ulbios Techsens" }, { 1450, "Bowery Farming, Inc." }, { 1451, "Ryobi Limited" }, { 1452, "EkkoSense Ltd" }, { 1453, "ClimaCool" }, { 0, NULL } }; static value_string_ext BACnetVendorIdentifiers_ext = VALUE_STRING_EXT_INIT(BACnetVendorIdentifiers); static int proto_bacapp = -1; static int hf_bacapp_type = -1; static int hf_bacapp_pduflags = -1; static int hf_bacapp_SEG = -1; static int hf_bacapp_MOR = -1; static int hf_bacapp_SA = -1; static int hf_bacapp_response_segments = -1; static int hf_bacapp_max_adpu_size = -1; static int hf_bacapp_invoke_id = -1; static int hf_bacapp_objectType = -1; static int hf_bacapp_object_name = -1; static int hf_bacapp_instanceNumber = -1; static int hf_bacapp_sequence_number = -1; static int hf_bacapp_window_size = -1; static int hf_bacapp_service = -1; static int hf_bacapp_NAK = -1; static int hf_bacapp_SRV = -1; static int hf_bacapp_notify_type = -1; static int hf_bacapp_event_type = -1; static int hf_bacapp_error_class = -1; static int hf_bacapp_error_code = -1; static int hf_Device_Instance_Range_Low_Limit = -1; static int hf_Device_Instance_Range_High_Limit = -1; static int hf_BACnetRejectReason = -1; static int hf_BACnetAbortReason = -1; static int hf_BACnetApplicationTagNumber = -1; static int hf_BACnetContextTagNumber = -1; static int hf_BACnetExtendedTagNumber = -1; static int hf_BACnetNamedTag = -1; static int hf_BACnetTagClass = -1; static int hf_BACnetCharacterSet = -1; static int hf_BACnetCodePage = -1; static int hf_bacapp_tag_lvt = -1; static int hf_bacapp_tag_ProcessId = -1; static int hf_bacapp_tag_to_state = -1; static int hf_bacapp_tag_from_state = -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; static int hf_bacapp_tag_mac_address_broadcast = -1; static int hf_bacapp_reserved_ashrea = -1; static int hf_bacapp_unused_bits = -1; static int hf_bacapp_bit = -1; static int hf_bacapp_complete_bitstring = -1; /* present value */ static int hf_bacapp_present_value_null = -1; static int hf_bacapp_present_value_bool = -1; static int hf_bacapp_present_value_unsigned = -1; static int hf_bacapp_present_value_signed = -1; static int hf_bacapp_present_value_real = -1; static int hf_bacapp_present_value_double = -1; static int hf_bacapp_present_value_octet_string = -1; static int hf_bacapp_present_value_char_string = -1; static int hf_bacapp_present_value_bit_string = -1; static int hf_bacapp_present_value_enum_index = -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_fragment_count = -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; static gint ett_bacapp_tag = -1; static gint ett_bacapp_list = -1; static gint ett_bacapp_value = -1; static expert_field ei_bacapp_bad_length = EI_INIT; static expert_field ei_bacapp_bad_tag = EI_INIT; static expert_field ei_bacapp_opening_tag = EI_INIT; static expert_field ei_bacapp_max_recursion_depth_reached = EI_INIT; static gint32 propertyIdentifier = -1; static gint32 propertyArrayIndex = -1; static guint32 object_type = 4096; static guint8 bacapp_flags = 0; static guint8 bacapp_seq = 0; /* Defined to allow vendor identifier registration of private transfer dissectors */ static dissector_table_t bacapp_dissector_table; /* Stat: BACnet Packets sorted by IP */ bacapp_info_value_t bacinfo; static const gchar* st_str_packets_by_ip = "BACnet Packets by IP"; static const gchar* st_str_packets_by_ip_dst = "By Destination"; static const gchar* st_str_packets_by_ip_src = "By Source"; static int st_node_packets_by_ip = -1; static int st_node_packets_by_ip_dst = -1; static int st_node_packets_by_ip_src = -1; static void bacapp_packet_stats_tree_init(stats_tree* st) { st_node_packets_by_ip = stats_tree_create_pivot(st, st_str_packets_by_ip, 0); st_node_packets_by_ip_src = stats_tree_create_node(st, st_str_packets_by_ip_src, st_node_packets_by_ip, STAT_DT_INT, TRUE); st_node_packets_by_ip_dst = stats_tree_create_node(st, st_str_packets_by_ip_dst, st_node_packets_by_ip, STAT_DT_INT, TRUE); } static gchar * bacapp_get_address_label(const char *tag, address *addr) { gchar *addr_str, *label_str; addr_str = address_to_str(NULL, addr); label_str = wmem_strconcat(NULL, tag, addr_str, NULL); wmem_free(NULL, addr_str); return label_str; } static tap_packet_status bacapp_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p, tap_flags_t flags _U_) { int packets_for_this_dst; int packets_for_this_src; int service_for_this_dst; int service_for_this_src; int src_for_this_dst; int dst_for_this_src; int objectid_for_this_dst; int objectid_for_this_src; int instanceid_for_this_dst; int instanceid_for_this_src; gchar *dststr; gchar *srcstr; const bacapp_info_value_t *binfo = (const bacapp_info_value_t *)p; srcstr = bacapp_get_address_label("Src: ", &pinfo->src); dststr = bacapp_get_address_label("Dst: ", &pinfo->dst); tick_stat_node(st, st_str_packets_by_ip, 0, TRUE); packets_for_this_dst = tick_stat_node(st, st_str_packets_by_ip_dst, st_node_packets_by_ip, TRUE); packets_for_this_src = tick_stat_node(st, st_str_packets_by_ip_src, st_node_packets_by_ip, TRUE); src_for_this_dst = tick_stat_node(st, dststr, packets_for_this_dst, TRUE); dst_for_this_src = tick_stat_node(st, srcstr, packets_for_this_src, TRUE); service_for_this_src = tick_stat_node(st, dststr, dst_for_this_src, TRUE); service_for_this_dst = tick_stat_node(st, srcstr, src_for_this_dst, TRUE); if (binfo->service_type) { objectid_for_this_dst = tick_stat_node(st, binfo->service_type, service_for_this_dst, TRUE); objectid_for_this_src = tick_stat_node(st, binfo->service_type, service_for_this_src, TRUE); if (binfo->object_ident) { instanceid_for_this_dst = tick_stat_node(st, binfo->object_ident, objectid_for_this_dst, TRUE); tick_stat_node(st, binfo->instance_ident, instanceid_for_this_dst, FALSE); instanceid_for_this_src = tick_stat_node(st, binfo->object_ident, objectid_for_this_src, TRUE); tick_stat_node(st, binfo->instance_ident, instanceid_for_this_src, FALSE); } } wmem_free(NULL, srcstr); wmem_free(NULL, dststr); return TAP_PACKET_REDRAW; } /* Stat: BACnet Packets sorted by Service */ static const gchar* st_str_packets_by_service = "BACnet Packets by Service"; static int st_node_packets_by_service = -1; static void bacapp_service_stats_tree_init(stats_tree* st) { st_node_packets_by_service = stats_tree_create_pivot(st, st_str_packets_by_service, 0); } static tap_packet_status bacapp_stats_tree_service(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p, tap_flags_t flags _U_) { int servicetype; int src, dst; int objectid; gchar *dststr; gchar *srcstr; const bacapp_info_value_t *binfo = (const bacapp_info_value_t *)p; srcstr = bacapp_get_address_label("Src: ", &pinfo->src); dststr = bacapp_get_address_label("Dst: ", &pinfo->dst); tick_stat_node(st, st_str_packets_by_service, 0, TRUE); if (binfo->service_type) { servicetype = tick_stat_node(st, binfo->service_type, st_node_packets_by_service, TRUE); src = tick_stat_node(st, srcstr, servicetype, TRUE); dst = tick_stat_node(st, dststr, src, TRUE); if (binfo->object_ident) { objectid = tick_stat_node(st, binfo->object_ident, dst, TRUE); tick_stat_node(st, binfo->instance_ident, objectid, FALSE); } } wmem_free(NULL, srcstr); wmem_free(NULL, dststr); return TAP_PACKET_REDRAW; } /* Stat: BACnet Packets sorted by Object Type */ static const gchar* st_str_packets_by_objectid = "BACnet Packets by Object Type"; static int st_node_packets_by_objectid = -1; static void bacapp_objectid_stats_tree_init(stats_tree* st) { st_node_packets_by_objectid = stats_tree_create_pivot(st, st_str_packets_by_objectid, 0); } static tap_packet_status bacapp_stats_tree_objectid(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p, tap_flags_t flags _U_) { int servicetype; int src, dst; int objectid; gchar *dststr; gchar *srcstr; const bacapp_info_value_t *binfo = (const bacapp_info_value_t *)p; srcstr = bacapp_get_address_label("Src: ", &pinfo->src); dststr = bacapp_get_address_label("Dst: ", &pinfo->dst); tick_stat_node(st, st_str_packets_by_objectid, 0, TRUE); if (binfo->object_ident) { objectid = tick_stat_node(st, binfo->object_ident, st_node_packets_by_objectid, TRUE); src = tick_stat_node(st, srcstr, objectid, TRUE); dst = tick_stat_node(st, dststr, src, TRUE); if (binfo->service_type) { servicetype = tick_stat_node(st, binfo->service_type, dst, TRUE); tick_stat_node(st, binfo->instance_ident, servicetype, FALSE); } } wmem_free(NULL, srcstr); wmem_free(NULL, dststr); return TAP_PACKET_REDRAW; } /* Stat: BACnet Packets sorted by Instance No */ static const gchar* st_str_packets_by_instanceid = "BACnet Packets by Instance ID"; static int st_node_packets_by_instanceid = -1; static void bacapp_instanceid_stats_tree_init(stats_tree* st) { st_node_packets_by_instanceid = stats_tree_create_pivot(st, st_str_packets_by_instanceid, 0); } static tap_packet_status bacapp_stats_tree_instanceid(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p, tap_flags_t flags _U_) { int servicetype; int src, dst; int instanceid; gchar *dststr; gchar *srcstr; const bacapp_info_value_t *binfo = (const bacapp_info_value_t *)p; srcstr = bacapp_get_address_label("Src: ", &pinfo->src); dststr = bacapp_get_address_label("Dst: ", &pinfo->dst); tick_stat_node(st, st_str_packets_by_instanceid, 0, TRUE); if (binfo->object_ident) { instanceid = tick_stat_node(st, binfo->instance_ident, st_node_packets_by_instanceid, TRUE); src = tick_stat_node(st, srcstr, instanceid, TRUE); dst = tick_stat_node(st, dststr, src, TRUE); if (binfo->service_type) { servicetype = tick_stat_node(st, binfo->service_type, dst, TRUE); tick_stat_node(st, binfo->object_ident, servicetype, FALSE); } } wmem_free(NULL, srcstr); wmem_free(NULL, dststr); return TAP_PACKET_REDRAW; } /* register all BACnet Ststistic trees */ static void register_bacapp_stat_trees(void) { stats_tree_register("bacapp", "bacapp_ip", "BACnet/Packets sorted by IP", 0, bacapp_stats_tree_packet, bacapp_packet_stats_tree_init, NULL); stats_tree_register("bacapp", "bacapp_service", "BACnet/Packets sorted by Service", 0, bacapp_stats_tree_service, bacapp_service_stats_tree_init, NULL); stats_tree_register("bacapp", "bacapp_objectid", "BACnet/Packets sorted by Object Type", 0, bacapp_stats_tree_objectid, bacapp_objectid_stats_tree_init, NULL); stats_tree_register("bacapp", "bacapp_instanceid", "BACnet/Packets sorted by Instance ID", 0, bacapp_stats_tree_instanceid, bacapp_instanceid_stats_tree_init, NULL); } /* 'data' must be allocated with wmem packet scope */ static gint updateBacnetInfoValue(gint whichval, const gchar *data) { if (whichval == BACINFO_SERVICE) { bacinfo.service_type = data; return 0; } if (whichval == BACINFO_INVOKEID) { bacinfo.invoke_id = data; return 0; } if (whichval == BACINFO_OBJECTID) { bacinfo.object_ident = data; return 0; } if (whichval == BACINFO_INSTANCEID) { bacinfo.instance_ident = data; return 0; } return -1; } static const fragment_items msg_frag_items = { /* Fragment subtrees */ &ett_msg_fragment, &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, &hf_msg_fragment_count, /* Reassembled in field */ &hf_msg_reassembled_in, /* Reassembled length field */ &hf_msg_reassembled_length, /* Reassembled data field */ NULL, /* Tag */ "Message fragments" }; #if 0 /* if BACnet uses the reserved values, then patch the corresponding values here, maximum 16 values are defined */ /* FIXME: fGetMaxAPDUSize is commented out, as it is not used. It was used to set variables which were not later used. */ 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]; } #endif static const char* val_to_split_str(guint32 val, guint32 split_val, const value_string *vs, const char *fmt, const char *split_fmt) G_GNUC_PRINTF(4, 0) G_GNUC_PRINTF(5, 0); /* 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, const char *fmt, const char *split_fmt) { if (val < split_val) return val_to_str(val, vs, fmt); else return val_to_str(val, vs, split_fmt); } /* 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) { return (tag & 0x07) == 5; } static gboolean tag_is_opening(guint8 tag) { return (tag & 0x07) == 6; } static gboolean tag_is_closing(guint8 tag) { return (tag & 0x07) == 7; } /* 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) { return (tag & 0x08) != 0; } static gboolean tag_is_extended_tag_number(guint8 tag) { return ((tag & 0xF0) == 0xF0); } static guint32 object_id_type(guint32 object_identifier) { return ((object_identifier >> 22) & 0x3FF); } static guint32 object_id_instance(guint32 object_identifier) { return (object_identifier & 0x3FFFFF); } static guint fTagNo(tvbuff_t *tvb, guint offset) { return (guint)(tvb_get_guint8(tvb, offset) >> 4); } 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); break; case 2: *val = tvb_get_ntohs(tvb, offset); break; case 3: *val = tvb_get_ntoh24(tvb, offset); break; case 4: *val = tvb_get_ntohl(tvb, offset); break; default: valid = FALSE; break; } return valid; } static gboolean 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; for (i = 0; i < lvt; i++) { data = tvb_get_guint8(tvb, offset+i); value = (value << 8) + data; } *val = value; } return valid; } /* BACnet Signed Value uses 2's complement notation, but with a twist: All signed integers shall be encoded in the smallest number of octets possible. That is, the first octet of any multi-octet encoded value shall not be X'00' if the most significant bit (bit 7) of the second octet is 0, and the first octet shall not be X'FF' if the most significant bit of the second octet is 1. ASHRAE-135-2004-20.2.5 */ static gboolean fSigned64(tvbuff_t *tvb, guint offset, guint32 lvt, gint64 *val) { gboolean valid = FALSE; gint64 value = 0; guint8 data; guint32 i; /* we can only handle 7 bytes for a 64-bit value due to signed-ness */ if (lvt && (lvt <= 7)) { valid = TRUE; data = tvb_get_guint8(tvb, offset); if ((data & 0x80) != 0) value = (~G_GUINT64_CONSTANT(0) << 8) | data; else value = data; for (i = 1; i < lvt; i++) { data = tvb_get_guint8(tvb, offset+i); value = ((guint64)value << 8) | data; } *val = value; } return valid; } static guint fTagHeaderTree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 *tag_no, guint8* tag_info, guint32 *lvt) { proto_item *ti = NULL; guint8 tag; guint8 value; guint tag_len = 1; guint lvt_len = 1; /* used for tree display of lvt */ guint lvt_offset; /* used for tree display of lvt */ lvt_offset = 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. */ if (tag_is_context_specific(tag)) *tag_info = tag & 0x0F; *tag_no = tag >> 4; 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 */ lvt_offset += tag_len; value = tvb_get_guint8(tvb, lvt_offset); tag_len++; if (value == 254) { /* length is encoded with 16 Bits */ *lvt = tvb_get_ntohs(tvb, lvt_offset+1); tag_len += 2; lvt_len += 2; } else if (value == 255) { /* length is encoded with 32 Bits */ *lvt = tvb_get_ntohl(tvb, lvt_offset+1); tag_len += 4; lvt_len += 4; } else *lvt = value; } if (tree) { proto_tree *subtree; if (tag_is_opening(tag)) { subtree = proto_tree_add_subtree_format(tree, tvb, offset, tag_len, ett_bacapp_tag, &ti, "{[%u]", *tag_no ); } else if (tag_is_closing(tag)) { subtree = proto_tree_add_subtree_format(tree, tvb, offset, tag_len, ett_bacapp_tag, &ti, "}[%u]", *tag_no ); } else if (tag_is_context_specific(tag)) { subtree = proto_tree_add_subtree_format(tree, tvb, offset, tag_len, ett_bacapp_tag, &ti, "Context Tag: %u, Length/Value/Type: %u", *tag_no, *lvt); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, tag_len, ett_bacapp_tag, &ti, "Application Tag: %s, Length/Value/Type: %u", val_to_str(*tag_no, BACnetApplicationTagNumber, ASHRAE_Reserved_Fmt), *lvt); } /* details if needed */ proto_tree_add_item(subtree, hf_BACnetTagClass, tvb, offset, 1, ENC_BIG_ENDIAN); if (tag_is_extended_tag_number(tag)) { proto_tree_add_uint_format(subtree, hf_BACnetContextTagNumber, tvb, offset, 1, tag, "Extended Tag Number"); proto_tree_add_item(subtree, hf_BACnetExtendedTagNumber, tvb, offset + 1, 1, ENC_BIG_ENDIAN); } else { if (tag_is_context_specific(tag)) proto_tree_add_item(subtree, hf_BACnetContextTagNumber, tvb, offset, 1, ENC_BIG_ENDIAN); else proto_tree_add_item(subtree, hf_BACnetApplicationTagNumber, tvb, offset, 1, ENC_BIG_ENDIAN); } if (tag_is_closing(tag) || tag_is_opening(tag)) proto_tree_add_item(subtree, hf_BACnetNamedTag, tvb, offset, 1, ENC_BIG_ENDIAN); else if (tag_is_extended_value(tag)) { proto_tree_add_item(subtree, hf_BACnetNamedTag, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_uint(subtree, hf_bacapp_tag_lvt, tvb, lvt_offset, lvt_len, *lvt); } else proto_tree_add_uint(subtree, hf_bacapp_tag_lvt, tvb, lvt_offset, lvt_len, *lvt); } /* if (tree) */ if (*lvt > tvb_reported_length(tvb)) { expert_add_info_format(pinfo, ti, &ei_bacapp_bad_length, "LVT length too long: %d > %d", *lvt, tvb_reported_length(tvb)); *lvt = 1; } return tag_len; } static guint fTagHeader(tvbuff_t *tvb, packet_info *pinfo, guint offset, guint8 *tag_no, guint8* tag_info, guint32 *lvt) { return fTagHeaderTree(tvb, pinfo, NULL, offset, tag_no, tag_info, lvt); } static guint fNullTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree; subtree = proto_tree_add_subtree_format(tree, tvb, offset, 1, ett_bacapp_tag, NULL, "%sNULL", label); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset + 1; } static guint fBooleanTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no, tag_info; guint32 lvt = 0; proto_tree *subtree; guint bool_len = 1; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_info && lvt == 1) { lvt = tvb_get_guint8(tvb, offset+1); ++bool_len; } subtree = proto_tree_add_subtree_format(tree, tvb, offset, bool_len, ett_bacapp_tag, NULL, "%s%s", label, lvt == 0 ? "FALSE" : "TRUE"); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset + bool_len; } static guint fUnsignedTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint64 val = 0; guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* only support up to an 8 byte (64-bit) integer */ if (fUnsigned64(tvb, offset + tag_len, lvt, &val)) subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s(Unsigned) %" PRIu64, label, val); else subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s - %u octets (Unsigned)", label, lvt); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } static guint fDevice_Instance(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, int hf) { guint8 tag_no, tag_info; guint32 lvt, safe_lvt; guint tag_len; proto_item *ti; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (lvt > 4) safe_lvt = 4; else safe_lvt = lvt; ti = proto_tree_add_item(tree, hf, tvb, offset+tag_len, safe_lvt, ENC_BIG_ENDIAN); if (lvt != safe_lvt) expert_add_info_format(pinfo, ti, &ei_bacapp_bad_length, "This field claims to be an impossible %u bytes, while the max is %u", lvt, safe_lvt); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } /* set split_val to zero when not needed */ static guint fEnumeratedTagSplit(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *vs, guint32 split_val) { guint32 val = 0; guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* only support up to a 4 byte (32-bit) enumeration */ if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) { if (vs) subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s %s (%u)", label, val_to_split_str(val, split_val, vs, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), val); else subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s %u", label, val); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s - %u octets (enumeration)", label, lvt); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } static guint fEnumeratedTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *vs) { return fEnumeratedTagSplit(tvb, pinfo, tree, offset, label, vs, 0); } static guint fSignedTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { gint64 val = 0; guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fSigned64(tvb, offset + tag_len, lvt, &val)) subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s(Signed) %" PRId64, label, val); else subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s - %u octets (Signed)", label, lvt); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } static guint fRealTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no, tag_info; guint32 lvt; guint tag_len; gfloat f_val; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); f_val = tvb_get_ntohieee_float(tvb, offset+tag_len); subtree = proto_tree_add_subtree_format(tree, tvb, offset, 4+tag_len, ett_bacapp_tag, NULL, "%s%f (Real)", label, f_val); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+4; } static guint fDoubleTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no, tag_info; guint32 lvt; guint tag_len; gdouble d_val; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); d_val = tvb_get_ntohieee_double(tvb, offset+tag_len); subtree = proto_tree_add_subtree_format(tree, tvb, offset, 8+tag_len, ett_bacapp_tag, NULL, "%s%f (Double)", label, d_val); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+8; } static guint fProcessId(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 val = 0, lvt; guint8 tag_no, tag_info; proto_item *ti; proto_tree *subtree; guint tag_len; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) { ti = proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, offset, lvt+tag_len, val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "Process Identifier - %u octets (Signed)", lvt); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += tag_len + lvt; return offset; } static guint fPresentValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const value_string *vs, guint32 split_val, BacappPresentValueType type) { // tag vars guint32 lvt; guint8 tag_no, tag_info; guint tag_len; guint curr_offset = offset; // tree vars proto_item *tree_item = NULL; proto_tree *subtree = NULL; // dissection vars guint bool_len = 1; guint64 unsigned_val = 0; gint64 signed_val = 0; gfloat float_val; gdouble double_val; guint32 enum_index = 0; guint32 object_id; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch(type) { case BACAPP_PRESENT_VALUE_NULL: tree_item = proto_tree_add_string(tree, hf_bacapp_present_value_null, tvb, offset, lvt+tag_len, "NULL"); curr_offset += 1; break; case BACAPP_PRESENT_VALUE_BOOL: if (tag_info && lvt == 1) { lvt = tvb_get_guint8(tvb, offset+1); bool_len++; } tree_item = proto_tree_add_boolean(tree, hf_bacapp_present_value_bool, tvb, offset, bool_len, lvt); curr_offset += bool_len; break; case BACAPP_PRESENT_VALUE_UNSIGNED: if (fUnsigned64(tvb, offset + tag_len, lvt, &unsigned_val)) tree_item = proto_tree_add_uint64(tree, hf_bacapp_present_value_unsigned, tvb, offset, lvt+tag_len, unsigned_val); curr_offset += tag_len + lvt; break; case BACAPP_PRESENT_VALUE_SIGNED: if (fSigned64(tvb, offset + tag_len, lvt, &signed_val)) tree_item = proto_tree_add_int64(tree, hf_bacapp_present_value_signed, tvb, offset, lvt+tag_len, signed_val); curr_offset += tag_len + lvt; break; case BACAPP_PRESENT_VALUE_REAL: float_val = tvb_get_ntohieee_float(tvb, offset+tag_len); double_val = (gdouble) float_val; tree_item = proto_tree_add_double(tree, hf_bacapp_present_value_real, tvb, offset, lvt+tag_len, double_val); curr_offset += tag_len + lvt; break; case BACAPP_PRESENT_VALUE_DOUBLE: double_val = tvb_get_ntohieee_double(tvb, offset+tag_len); tree_item = proto_tree_add_double(tree, hf_bacapp_present_value_double, tvb, offset, lvt+tag_len, double_val); curr_offset += tag_len + lvt; break; case BACAPP_PRESENT_VALUE_OCTET_STRING: if (lvt > 0) tree_item = proto_tree_add_item(tree, hf_bacapp_present_value_octet_string, tvb, offset, lvt+tag_len, ENC_NA); curr_offset += tag_len + lvt; break; case BACAPP_PRESENT_VALUE_CHARACTER_STRING: curr_offset = fCharacterStringBase(tvb, pinfo, tree, offset, NULL, TRUE, FALSE); break; case BACAPP_PRESENT_VALUE_BIT_STRING: curr_offset = fBitStringTagVSBase(tvb, pinfo, tree, offset, NULL, NULL, TRUE); break; case BACAPP_PRESENT_VALUE_ENUM: if (fUnsigned32(tvb, offset+tag_len, lvt, &enum_index)) { if (vs) { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "Present Value (enum value): %s", val_to_split_str(enum_index, split_val, vs, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt)); proto_tree_add_uint(subtree, hf_bacapp_present_value_enum_index, tvb, offset, lvt+tag_len, enum_index); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { tree_item = proto_tree_add_uint(tree, hf_bacapp_present_value_enum_index, tvb, offset, lvt+tag_len, enum_index); } } curr_offset += tag_len + lvt; break; case BACAPP_PRESENT_VALUE_DATE: curr_offset = fDate(tvb, pinfo, tree, offset, "Date: "); break; case BACAPP_PRESENT_VALUE_TIME: curr_offset = fTime(tvb, pinfo, tree, offset, "Time: "); break; case BACAPP_PRESENT_VALUE_OBJECT_IDENTIFIER: object_id = tvb_get_ntohl(tvb, offset+tag_len); object_type = object_id_type(object_id); subtree = proto_tree_add_subtree_format(tree, tvb, offset, tag_len + 4, ett_bacapp_tag, NULL, "Present Value (enum value): %s", val_to_split_str(object_type, 128, BACnetObjectType, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt)); proto_tree_add_uint(subtree, hf_bacapp_present_value_enum_index, tvb, offset, lvt+tag_len, object_type); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); curr_offset += tag_len + lvt; break; default: curr_offset += tag_len + lvt; break; } if (tree_item != NULL && subtree == NULL) { subtree = proto_item_add_subtree(tree_item, ett_bacapp_value); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } return curr_offset; } static guint fEventType(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 val = 0, lvt; guint8 tag_no, tag_info; proto_item *ti; proto_tree *subtree; guint tag_len; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) { ti = proto_tree_add_uint(tree, hf_bacapp_event_type, tvb, offset, lvt+tag_len, val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "Event Type - %u octets (Signed)", lvt); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += tag_len + lvt; return offset; } static guint fNotifyType(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 val = 0, lvt; guint8 tag_no, tag_info; proto_item *ti; proto_tree *subtree; guint tag_len; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) { ti = proto_tree_add_uint(tree, hf_bacapp_notify_type, tvb, offset, lvt+tag_len, val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "Notify Type - %u octets (Signed)", lvt); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += tag_len + lvt; return offset; } static guint fToState(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 val = 0, lvt; guint8 tag_no, tag_info; proto_item *ti; proto_tree *subtree; guint tag_len; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) { ti = proto_tree_add_uint(tree, hf_bacapp_tag_to_state, tvb, offset, lvt+tag_len, val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "To State - %u octets (Signed)", lvt); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += tag_len + lvt; return offset; } static guint fFromState(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 val = 0, lvt; guint8 tag_no, tag_info; proto_item *ti; proto_tree *subtree; guint tag_len; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) { ti = proto_tree_add_uint(tree, hf_bacapp_tag_from_state, tvb, offset, lvt+tag_len, val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "From State - %u octets (Signed)", lvt); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += tag_len + lvt; return offset; } static guint fTimeSpan(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint32 val = 0, lvt; guint8 tag_no, tag_info; proto_tree *subtree; guint tag_len; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s (hh.mm.ss): %d.%02d.%02d%s", label, (val / 3600), ((val % 3600) / 60), (val % 60), val == 0 ? " (indefinite)" : ""); else subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s - %u octets (Signed)", label, lvt); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } static guint fWeekNDay(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 month, weekOfMonth, dayOfWeek; guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); 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); subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%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")); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } static guint fDate(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint32 year, month, day, weekday; guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); year = tvb_get_guint8(tvb, offset+tag_len); month = tvb_get_guint8(tvb, offset+tag_len+1); day = tvb_get_guint8(tvb, offset+tag_len+2); weekday = tvb_get_guint8(tvb, offset+tag_len+3); if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255)) { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%sany", label); } else if (year != 255) { year += 1900; subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s%s %d, %d, (Day of Week = %s)", label, val_to_str(month, months, "month (%d) not found"), day, year, val_to_str(weekday, day_of_week, "(%d) not found")); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s%s %d, any year, (Day of Week = %s)", label, val_to_str(month, months, "month (%d) not found"), day, val_to_str(weekday, day_of_week, "(%d) not found")); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } static guint fTime(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint32 hour, minute, second, msec, lvt; guint8 tag_no, tag_info; guint tag_len; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); hour = tvb_get_guint8(tvb, offset+tag_len); minute = tvb_get_guint8(tvb, offset+tag_len+1); second = tvb_get_guint8(tvb, offset+tag_len+2); msec = tvb_get_guint8(tvb, offset+tag_len+3); if ((hour == 255) && (minute == 255) && (second == 255) && (msec == 255)) subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%sany", label); else subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s%d:%02d:%02d.%d %s = %02d:%02d:%02d.%d", label, hour > 12 ? hour - 12 : hour, minute, second, msec, hour >= 12 ? "P.M." : "A.M.", hour, minute, second, msec); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } static guint fDateTime(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { proto_tree *subtree = tree; if (label != NULL) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 10, ett_bacapp_value, NULL, label); } offset = fDate(tvb, pinfo, subtree, offset, "Date: "); return fTime(tvb, pinfo, subtree, offset, "Time: "); } static guint fTimeValue(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { /* closing Tag, but not for me */ return offset; } offset = fTime(tvb, pinfo, tree, offset, "Time: "); offset = fApplicationTypes(tvb, pinfo, tree, offset, "Value: "); if (offset <= lastoffset) break; /* exit loop if nothing happens inside */ } return offset; } static guint fCalendarEntry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; switch (fTagNo(tvb, offset)) { case 0: /* Date */ offset = fDate(tvb, pinfo, tree, offset, "Date: "); break; case 1: /* dateRange */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateRange(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* BACnetWeekNDay */ offset = fWeekNDay(tvb, pinfo, tree, offset); break; default: return offset; } return offset; } static guint fEventTimeStamps( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 lvt = 0; proto_tree* subtree = tree; if (tvb_reported_length_remaining(tvb, offset) > 0) { subtree = proto_tree_add_subtree(tree, tvb, offset, lvt, ett_bacapp_tag, NULL, "eventTimeStamps"); offset = fTimeStamp(tvb, pinfo, subtree, offset, "TO-OFFNORMAL timestamp: "); offset = fTimeStamp(tvb, pinfo, subtree, offset, "TO-FAULT timestamp: "); offset = fTimeStamp(tvb, pinfo, subtree, offset, "TO-NORMAL timestamp: "); } return offset; } static guint fTimeStamp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no = 0, tag_info = 0; guint32 lvt = 0; 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, pinfo, tree, offset, label?label:"time: "); break; case 1: /* sequenceNumber */ offset = fUnsignedTag(tvb, pinfo, tree, offset, label?label:"sequence number: "); break; case 2: /* dateTime */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, label?label:"date time: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } } return offset; } static guint fClientCOV(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { if (tvb_reported_length_remaining(tvb, offset) > 0) { offset = fApplicationTypes(tvb, pinfo, 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, packet_info *pinfo, proto_tree *tree, guint offset) { if (tvb_reported_length_remaining(tvb, offset) > 0) { offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, "valid Days: ", BACnetDaysOfWeek); offset = fTime(tvb, pinfo, tree, offset, "from time: "); offset = fTime(tvb, pinfo, tree, offset, "to time: "); offset = fRecipient(tvb, pinfo, tree, offset); offset = fProcessId(tvb, pinfo, tree, offset); offset = fApplicationTypes(tvb, pinfo, tree, offset, "issue confirmed notifications: "); offset = fBitStringTagVS(tvb, pinfo, tree, offset, "transitions: ", BACnetEventTransitionBits); } return offset; } static guint fOctetString(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, guint32 lvt) { gchar *tmp; guint start = offset; guint8 tag_no, tag_info; proto_tree *subtree = tree; offset += fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (lvt > 0) { tmp = tvb_bytes_to_str(pinfo->pool, tvb, offset, lvt); subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt, ett_bacapp_tag, NULL, "%s %s", label, tmp); offset += lvt; } fTagHeaderTree(tvb, pinfo, subtree, start, &tag_no, &tag_info, &lvt); return offset; } static guint fMacAddress(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, guint32 lvt) { guint start = offset; guint8 tag_no, tag_info; proto_tree* subtree = tree; offset += fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* just add the label, with the tagHeader information in its subtree */ subtree = proto_tree_add_subtree(tree, tvb, offset, lvt, ett_bacapp_tag, NULL, label); if (lvt == 6) { /* we have 6 Byte IP Address with 4 Octets IPv4 and 2 Octets Port Information */ proto_tree_add_item(tree, hf_bacapp_tag_IPV4, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(tree, hf_bacapp_tag_PORT, tvb, offset+4, 2, ENC_BIG_ENDIAN); } else if (lvt == 18) { /* we have 18 Byte IP Address with 16 Octets IPv6 and 2 Octets Port Information */ proto_tree_add_item(tree, hf_bacapp_tag_IPV6, tvb, offset, 16, ENC_NA); proto_tree_add_item(tree, hf_bacapp_tag_PORT, tvb, offset+16, 2, ENC_BIG_ENDIAN); } else { /* we have 1 Byte MS/TP Address or anything else interpreted as an address */ subtree = proto_tree_add_subtree(tree, tvb, offset, lvt, ett_bacapp_tag, NULL, tvb_bytes_to_str(pinfo->pool, tvb, offset, lvt)); } offset += lvt; fTagHeaderTree(tvb, pinfo, subtree, start, &tag_no, &tag_info, &lvt); return offset; } static guint fAddress(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint offs; offset = fUnsignedTag(tvb, pinfo, tree, offset, "network-number"); offs = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (lvt == 0) { proto_tree_add_item(tree, hf_bacapp_tag_mac_address_broadcast, tvb, offset, offs, ENC_NA); offset += offs; } else offset = fMacAddress(tvb, pinfo, tree, offset, "MAC-address: ", lvt); return offset; } static guint fSessionKey(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { offset = fOctetString(tvb, pinfo, tree, offset, "session key: ", 8); return fAddress(tvb, pinfo, tree, offset); } static guint fObjectIdentifier(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no, tag_info; guint32 lvt; guint tag_length; proto_tree *subtree; guint32 object_id; tag_length = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); object_id = tvb_get_ntohl(tvb, offset+tag_length); object_type = object_id_type(object_id); subtree = proto_tree_add_subtree_format(tree, tvb, offset, tag_length + 4, ett_bacapp_tag, NULL, "%s%s, %u", label, val_to_split_str(object_type, 128, BACnetObjectType, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), object_id_instance(object_id)); 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)); /* update BACnet Statistics */ updateBacnetInfoValue(BACINFO_OBJECTID, wmem_strdup(pinfo->pool, val_to_split_str(object_type, 128, BACnetObjectType, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt))); updateBacnetInfoValue(BACINFO_INSTANCEID, wmem_strdup_printf(pinfo->pool, "Instance ID: %u", object_id_instance(object_id))); /* here are the details of how we arrived at the above text */ fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += tag_length; proto_tree_add_item(subtree, hf_bacapp_objectType, tvb, offset, 4, ENC_BIG_ENDIAN); proto_tree_add_item(subtree, hf_bacapp_instanceNumber, tvb, offset, 4, ENC_BIG_ENDIAN); offset += 4; return offset; } static guint fObjectName(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fCharacterStringBase(tvb, pinfo, tree, offset, "Object Name", FALSE, TRUE); } static guint fRecipient(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_no < 2) { if (tag_no == 0) { /* device */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); } else { /* address */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fAddress(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } } return offset; } static guint fRecipientProcess(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *orgtree = tree; proto_tree *subtree; /* beginning of new item - indent and label */ tree = proto_tree_add_subtree(orgtree, tvb, offset, 1, ett_bacapp_value, NULL, "Recipient Process" ); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* recipient */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* show context open */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "Recipient"); /* add tree label and indent */ offset = fRecipient(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; case 1: /* processId */ offset = fProcessId(tvb, pinfo, tree, offset); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fCOVSubscription(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree; proto_tree *orgtree = tree; guint itemno = 1; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info) ) { return offset; } switch (tag_no) { case 0: /* recipient */ /* beginning of new item in list */ tree = proto_tree_add_subtree_format(orgtree, tvb, offset, 1, ett_bacapp_value, NULL, "Subscription %d",itemno); /* add tree label and indent */ itemno = itemno + 1; subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "Recipient"); /* add tree label and indent */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fRecipientProcess(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; case 1: /* MonitoredPropertyReference */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "Monitored Property Reference"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* IssueConfirmedNotifications - boolean */ offset = fBooleanTag(tvb, pinfo, tree, offset, "Issue Confirmed Notifications: "); break; case 3: /* TimeRemaining */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Time Remaining: "); break; case 4: /* COVIncrement */ offset = fRealTag(tvb, pinfo, tree, offset, "COV Increment: "); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAddressBinding(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); return fAddress(tvb, pinfo, tree, offset); } static guint fActionCommand(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tag_match) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; /* set the optional global properties to indicate not-used */ propertyArrayIndex = -1; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, 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, pinfo, subtree, offset, "DeviceIdentifier: "); break; case 1: /* objectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 2: /* propertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, subtree, offset); break; case 3: /* propertyArrayIndex */ offset = fPropertyArrayIndex(tvb, pinfo, subtree, offset); break; case 4: /* propertyValue */ offset = fPropertyValue(tvb, pinfo, subtree, offset, tag_info); break; case 5: /* priority */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "Priority: "); break; case 6: /* postDelay */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "Post Delay: "); break; case 7: /* quitOnFailure */ offset = fBooleanTag(tvb, pinfo, subtree, offset, "Quit On Failure: "); break; case 8: /* writeSuccessful */ offset = fBooleanTag(tvb, pinfo, subtree, offset, "Write Successful: "); break; 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, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; while (tvb_reported_length_remaining(tvb, offset) > 0) { lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { if ( tag_no != 0 ) /* don't eat the closing property tag, just return */ return offset; /* print closing tag of action list too */ fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); subtree = tree; offset += len; continue; } if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_tag, NULL, "Action List"); offset += fTagHeaderTree(tvb, pinfo, 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 fPropertyAccessResult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; guint32 save_object_type; guint32 save_inner_object_type; gint32 save_propertyIdentifier; /* save the external entry data because it might get overwritten here */ save_object_type = object_type; save_propertyIdentifier = propertyIdentifier; /* inner object type might get overwritten by device id */ save_inner_object_type = object_type; while (tvb_reported_length_remaining(tvb, offset) > 0) { lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* objectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); /* save the local object type because device id might overwrite it */ save_inner_object_type = object_type; break; case 1: /* propertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, tree, offset); break; case 2: /* propertyArrayIndex */ offset = fPropertyArrayIndex(tvb, pinfo, tree, offset); break; case 3: /* deviceIdentifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); /* restore the inner object type to decode the right property value */ object_type = save_inner_object_type; break; case 4: /* propertyValue */ offset = fPropertyValue(tvb, pinfo, tree, offset, tag_info); /* restore the external values for next loop */ object_type = save_object_type; propertyIdentifier = save_propertyIdentifier; break; case 5: /* propertyAccessError */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, tree, &ei_bacapp_bad_tag); } /* restore the external values for next loop */ object_type = save_object_type; propertyIdentifier = save_propertyIdentifier; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } /* restore the external values for next decoding */ object_type = save_object_type; propertyIdentifier = save_propertyIdentifier; return offset; } static guint fPropertyIdentifier(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_tree *subtree; const gchar *label = "Property Identifier"; propertyIdentifier = 0; /* global Variable */ tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* can we decode this value? */ if (fUnsigned32(tvb, offset+tag_len, lvt, (guint32 *)&propertyIdentifier)) { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "%s: %s (%u)", label, val_to_split_str(propertyIdentifier, 512, BACnetPropertyIdentifier, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), propertyIdentifier); 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; } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); proto_tree_add_item(subtree, hf_BACnetPropertyIdentifier, tvb, offset+tag_len, lvt, ENC_BIG_ENDIAN); return offset+tag_len+lvt; } static guint fPropertyArrayIndex(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_tree *subtree; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset + tag_len, lvt, (guint32 *)&propertyArrayIndex)) subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "property Array Index (Unsigned) %u", propertyArrayIndex); else subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "property Array Index - %u octets (Unsigned)", lvt); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset+tag_len+lvt; } static guint fChannelValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no, tag_info; guint32 lvt; if (tvb_reported_length_remaining(tvb, offset) > 0) { fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info) && tag_no == 0) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fLightingCommand(tvb, pinfo, tree, offset, "lighting-command: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else if (tag_is_opening(tag_info) && tag_no == 1) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fXyColor(tvb, pinfo, tree, offset, "xy-color: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else if (tag_is_opening(tag_info) && tag_no == 2) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fColorCommand(tvb, pinfo, tree, offset, "color-command: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else { if (tag_info) { offset = fContextTaggedValue(tvb, pinfo, tree, offset, label); } else { offset = fApplicationTypes(tvb, pinfo, tree, offset, label); } } } return offset; } static guint fCharacterString(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { return fCharacterStringBase(tvb, pinfo, tree, offset, label, FALSE, FALSE); } static guint fCharacterStringBase(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, gboolean present_val_dissect, gboolean object_name_dissect) { guint8 tag_no, tag_info, character_set; guint32 lvt, l; guint offs; const char *coding; guint8 *out; proto_tree *subtree; guint start = offset; if (tvb_reported_length_remaining(tvb, offset) > 0) { offs = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); offset += offs; character_set = tvb_get_guint8(tvb, offset); offset++; lvt--; /* Account for code page if DBCS */ if (character_set == IBM_MS_DBCS) { offset += 2; lvt -= 2; } do { l = MIN(lvt, 256); /* * XXX - are we guaranteed that these encoding * names correspond, on *all* platforms with * iconv(), to the encodings we want? * * Not necessarily. These specify "character sets" but * not the encodings. IBM/MS DBCS specifies that it uses * some IBM or MS double byte character set, but does not * specify the code page - there was a proposal to explicitly * add the code page, but that was apparently withdrawn in favor * of just deprecating using DBCS, as it never got past a draft * (One problem could be that IBM and MS code pages with the * same number are slightly different, and then there's non * IBM/MS unofficial ones that got used, sometimes conflicting * numbers.) Even if we assume that they certainly mean one * of the DBCS and not just any non ISO-8859-1 code page, there's * all four types of CJK to choose from. - * http://www.bacnet.org/Addenda/Add-135-2004k-PPR1-chair-approved.pdf * JIS C 6226 (now JIS X 0208) * http://www.bacnet.org/Addenda/Add-135-2008k.pdf * is a character set, which are supported by several different * encodings, the main types being ISO-2022-JP (JIS X 0202, * a 7 bit encoding), Shift-JIS (most common), and EUC-JP (UNIX). * It is unclear which encoding this refers to. * * If not (and perhaps even if so), we should * perhaps have our own iconv() implementation, * with a different name, so that we control the * encodings it supports and the names of those * encodings. * * We should also handle that in the general * string handling code, rather than making it * specific to the BACAPP dissector, as many * other dissectors need to handle various * character encodings. */ /** this decoding may be not correct for multi-byte characters, Lka */ switch (character_set) { case ANSI_X3_4: out = tvb_get_string_enc(pinfo->pool, tvb, offset, l, ENC_UTF_8); coding = "UTF-8"; break; case IBM_MS_DBCS: out = tvb_get_string_enc(pinfo->pool, tvb, offset, l, ENC_ASCII); coding = "IBM MS DBCS"; break; case JIS_C_6226: out = tvb_get_string_enc(pinfo->pool, tvb, offset, l, ENC_ASCII); coding = "JIS C 6226"; break; case ISO_10646_UCS4: out = tvb_get_string_enc(pinfo->pool, tvb, offset, l, ENC_UCS_4|ENC_BIG_ENDIAN); coding = "ISO 10646 UCS-4"; break; case ISO_10646_UCS2: out = tvb_get_string_enc(pinfo->pool, tvb, offset, l, ENC_UCS_2|ENC_BIG_ENDIAN); coding = "ISO 10646 UCS-2"; break; case ISO_8859_1: out = tvb_get_string_enc(pinfo->pool, tvb, offset, l, ENC_ISO_8859_1); coding = "ISO 8859-1"; break; default: /* Assume this is some form of extended ASCII, with one-byte code points for ASCII characters */ out = tvb_get_string_enc(pinfo->pool, tvb, offset, l, ENC_ASCII); coding = "unknown"; break; } if (present_val_dissect) { subtree = proto_tree_add_subtree(tree, tvb, offset, l, ett_bacapp_tag, NULL, "present-value"); proto_tree_add_string(subtree, hf_bacapp_present_value_char_string, tvb, offset, l, (const gchar*) out); } else if (object_name_dissect) { subtree = proto_tree_add_subtree(tree, tvb, offset, l, ett_bacapp_tag, NULL, label); proto_tree_add_string(subtree, hf_bacapp_object_name, tvb, offset, l, (const gchar*) out); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, l, ett_bacapp_tag, NULL, "%s%s '%s'", label, coding, out); } lvt -= l; offset += l; } while (lvt > 0); fTagHeaderTree(tvb, pinfo, subtree, start, &tag_no, &tag_info, &lvt); proto_tree_add_item(subtree, hf_BACnetCharacterSet, tvb, start+offs, 1, ENC_BIG_ENDIAN); if (character_set == IBM_MS_DBCS) { proto_tree_add_item(subtree, hf_BACnetCodePage, tvb, start+offs+1, 2, ENC_BIG_ENDIAN); } /* XXX - put the string value here */ } return offset; } static guint fBitStringTagVS(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *src) { return fBitStringTagVSBase(tvb, pinfo, tree, offset, label, src, FALSE); } static guint fBitStringTagVSBase(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *src, gboolean present_val_dissect) { guint8 tag_no, tag_info, tmp; gint j, unused, skip; guint start = offset; guint offs; guint32 lvt, i, numberOfBytes; char bf_arr[256 + 1]; proto_tree *subtree = tree; offs = fTagHeader(tvb, pinfo, 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 */ memset(bf_arr, 0, sizeof(bf_arr)); skip = 0; for (i = 0; i < numberOfBytes; i++) { tmp = tvb_get_guint8(tvb, (offset)+i + 1); if (i == numberOfBytes - 1) { skip = unused; } for (j = 0; j < 8 - skip; j++) { bf_arr[MIN(sizeof(bf_arr) - 2, (i * 8) + j)] = tmp & (1 << (7 - j)) ? 'T' : 'F'; } } if (!present_val_dissect) { subtree = proto_tree_add_subtree_format(tree, tvb, start, offs+lvt, ett_bacapp_tag, NULL, "%s(Bit String) (%s)", label, bf_arr); } else { subtree = proto_tree_add_subtree_format(tree, tvb, start, offs+lvt, ett_bacapp_tag, NULL, "present-value (%s)", bf_arr); } fTagHeaderTree(tvb, pinfo, subtree, start, &tag_no, &tag_info, &lvt); proto_tree_add_item(subtree, hf_bacapp_unused_bits, tvb, offset, 1, ENC_NA); memset(bf_arr, 0, sizeof(bf_arr)); skip = 0; for (i = 0; i < numberOfBytes; i++) { tmp = tvb_get_guint8(tvb, (offset)+i+1); if (i == numberOfBytes-1) { skip = unused; } for (j = 0; j < 8-skip; j++) { if (src != NULL) { proto_tree_add_boolean_format(subtree, hf_bacapp_bit, tvb, offset+i+1, 1, (tmp & (1 << (7 - j))), "%s = %s", val_to_str((guint) (i*8 +j), src, ASHRAE_Reserved_Fmt), (tmp & (1 << (7 - j))) ? "TRUE" : "FALSE"); } else { 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_bytes_format(subtree, hf_bacapp_complete_bitstring, tvb, offset, lvt, NULL, "B'%s'", bf_arr); } offset += lvt; return offset; } static guint fBitStringTag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { return fBitStringTagVS(tvb, pinfo, tree, offset, label, NULL); } /* handles generic application types, as well as enumerated and enumerations with reserved and proprietarty ranges (split) */ static guint 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_reported_length_remaining(tvb, offset) > 0) { tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (!tag_is_context_specific(tag_info)) { switch (tag_no) { case 0: /** NULL 20.2.2 */ offset = fNullTag(tvb, pinfo, tree, offset, label); break; case 1: /** BOOLEAN 20.2.3 */ offset = fBooleanTag(tvb, pinfo, tree, offset, label); break; case 2: /** Unsigned Integer 20.2.4 */ offset = fUnsignedTag(tvb, pinfo, tree, offset, label); break; case 3: /** Signed Integer 20.2.5 */ offset = fSignedTag(tvb, pinfo, tree, offset, label); break; case 4: /** Real 20.2.6 */ offset = fRealTag(tvb, pinfo, tree, offset, label); break; case 5: /** Double 20.2.7 */ offset = fDoubleTag(tvb, pinfo, tree, offset, label); break; case 6: /** Octet String 20.2.8 */ offset = fOctetString(tvb, pinfo, tree, offset, label, lvt); break; case 7: /** Character String 20.2.9 */ offset = fCharacterString(tvb, pinfo, tree, offset, label); break; case 8: /** Bit String 20.2.10 */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, label, src); break; case 9: /** Enumerated 20.2.11 */ offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, label, src, split_val); break; case 10: /** Date 20.2.12 */ offset = fDate(tvb, pinfo, tree, offset, label); break; case 11: /** Time 20.2.13 */ offset = fTime(tvb, pinfo, tree, offset, label); break; case 12: /** BACnetObjectIdentifier 20.2.14 */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 13: /* reserved for ASHRAE */ case 14: case 15: proto_tree_add_bytes_format(tree, hf_bacapp_reserved_ashrea, tvb, offset, lvt+tag_len, NULL, "%s'reserved for ASHRAE'", label); offset += lvt + tag_len; break; default: break; } } } return offset; } static guint fShedLevel(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* percent */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "shed percent: "); break; case 1: /* level */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "shed level: "); break; case 2: /* amount */ offset = fRealTag(tvb, pinfo, 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, pinfo, tree, offset, label, vs, 0); } static guint fApplicationTypes(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { return fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, label, NULL, 0); } static guint fContextTaggedValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint8 tag_no, tag_info; guint32 lvt; guint tag_len; proto_tree *subtree; gint tvb_len; (void)label; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* cap the the suggested length in case of bad data */ tvb_len = tvb_reported_length_remaining(tvb, offset+tag_len); if ((tvb_len >= 0) && ((guint32)tvb_len < lvt)) { lvt = tvb_len; } subtree = proto_tree_add_subtree_format(tree, tvb, offset+tag_len, lvt, ett_bacapp_tag, NULL, "Context Value (as %u DATA octets)", lvt); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset + tag_len + lvt; } /* BACnetPrescale ::= SEQUENCE { multiplier [0] Unsigned, moduloDivide [1] Unsigned } */ static guint fPrescale(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info) ) { return offset; } switch (tag_no) { case 0: /* multiplier */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Multiplier: "); break; case 1: /* moduloDivide */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Modulo Divide: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } /* BACnetScale ::= CHOICE { floatScale [0] REAL, integerScale [1] INTEGER } */ static guint fScale(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info) ) { return offset; } switch (tag_no) { case 0: /* floatScale */ offset = fRealTag(tvb, pinfo, tree, offset, "Float Scale: "); break; case 1: /* integerScale */ offset = fSignedTag(tvb, pinfo, tree, offset, "Integer Scale: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } /* BACnetAccumulatorRecord ::= SEQUENCE { timestamp [0] BACnetDateTime, presentValue [1] Unsigned, accumulatedValue [2] Unsigned, accumulatortStatus [3] ENUMERATED { normal (0), starting (1), recovered (2), abnormal (3), failed (4) } } */ static guint fLoggingRecord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info) ) { return offset; } switch (tag_no) { case 0: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "Timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* presentValue */ offset = fPresentValue(tvb, pinfo, tree, offset, NULL, 0, BACAPP_PRESENT_VALUE_UNSIGNED); break; case 2: /* accumulatedValue */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Accumulated Value: "); break; case 3: /* accumulatorStatus */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "Accumulator Status: ", BACnetAccumulatorStatus); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } /* SEQ OF Any enumeration (current usage is SEQ OF BACnetDoorAlarmState */ static guint fSequenceOfEnums(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *vs) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info) ) { return offset; } offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, label, vs); if ( offset <= lastoffset ) break; } return offset; } /* SEQ OF BACnetDeviceObjectReference (accessed as an array) } */ static guint fDoorMembers(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info) ) { return offset; } offset = fDeviceObjectReference(tvb, pinfo, tree, offset); if (offset <= lastoffset) break; } return offset; } /* SEQ OF ReadAccessSpecification */ static guint fListOfGroupMembers(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info) ) { return offset; } offset = fReadAccessSpecification(tvb, pinfo, tree, offset); if ( offset <= lastoffset ) break; } return offset; } static guint 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]; guint32 save_object_type; gboolean do_default_handling; if (propertyIdentifier >= 0) { snprintf(ar, sizeof(ar), "%s: ", val_to_split_str(propertyIdentifier, 512, BACnetPropertyIdentifier, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt)); } else { snprintf(ar, sizeof(ar), "Abstract Type: "); } unsigned recursion_depth = p_get_proto_depth(pinfo, proto_bacapp); if (++recursion_depth >= BACAPP_MAX_RECURSION_DEPTH) { proto_tree_add_expert(tree, pinfo, &ei_bacapp_max_recursion_depth_reached, tvb, 0, 0); return offset; } p_set_proto_depth(pinfo, proto_bacapp, recursion_depth); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { /* closing tag, but not for me */ if (depth <= 0) { goto cleanup; } } do_default_handling = FALSE; /* Application Tags */ switch (propertyIdentifier) { case 0: /* acked-transitions */ case 35: /* event-enable */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAcknowledgedTransitions); break; 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 7: /* alarm-values*/ switch (object_type) { case 21: /* life-point */ case 22: /* life-zone */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyState); break; case 30: /* access-door */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetDoorAlarmState); break; case 31: /* timer */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetTimerState); break; case 36: /* access-zone */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAccessZoneOccupancyState); break; case 39: /* bitstring-value */ default: if (tag_info) { if (tag_is_opening(tag_info)) { ++depth; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else if (tag_is_closing(tag_info)) { --depth; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else { offset = fContextTaggedValue(tvb, pinfo, tree, offset, ar); } } else { offset = fApplicationTypes(tvb, pinfo, tree, offset, ar); } break; } break; case 37: /* event-type */ offset = fEventType(tvb, pinfo, tree, offset); break; case 39: /* fault-values */ switch (object_type) { case 21: /* life-point */ case 22: /* life-zone */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyState); break; case 30: /* access-door */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetDoorAlarmState); break; case 31: /* timer */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetTimerState); break; case 36: /* access-zone */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAccessZoneOccupancyState); break; case 39: /* bitstring-value */ default: if (tag_info) { if (tag_is_opening(tag_info)) { ++depth; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else if (tag_is_closing(tag_info)) { --depth; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else { offset = fContextTaggedValue(tvb, pinfo, tree, offset, ar); } } else { offset = fApplicationTypes(tvb, pinfo, tree, offset, ar); } break; } break; case 30: /* BACnetAddressBinding */ case 331: /* last-key-server */ offset = fAddressBinding(tvb, pinfo, tree, offset); break; case 52: /* limit-enable */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLimitEnable); break; case 54: /* list of object property reference */ offset = fLOPR(tvb, pinfo, tree, offset); break; case 55: /* list-of-session-keys */ fSessionKey(tvb, pinfo, tree, offset); break; case 77: /* object-name */ offset = fObjectName(tvb, pinfo, tree, offset); break; case 79: /* object-type */ case 96: /* protocol-object-types-supported */ offset = fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, ar, BACnetObjectType, 128); break; case 97: /* Protocol-Services-Supported */ 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, pinfo, tree, offset, ar, BACnetSegmentation); break; case 111: /* Status-Flags */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetStatusFlags); break; case 112: /* System-Status */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetDeviceStatus); break; case 117: /* units */ case 455: /* car-load-units */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetEngineeringUnits); break; 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) { 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); } } break; case 19: /* controlled-variable-reference */ case 60: /* manipulated-variable-reference */ case 78: /* object-property-reference */ case 181: /* input-reference */ case 355: /* event-algorithm-inhibit-reference */ offset = fObjectPropertyReference(tvb, pinfo, tree, offset); break; case 132: /* log-device-object-property */ offset = fDeviceObjectPropertyReference(tvb, pinfo, tree, offset); break; case 109: /* Setpoint-Reference */ /* setpoint-Reference is actually BACnetSetpointReference which is a SEQ of [0] */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetObjectPropertyReference(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 123: /* weekly-schedule -- accessed as a BACnetARRAY */ if (object_type < 128) { 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 */ if ( object_type == 61 ) offset = fAuditLogRecord(tvb, pinfo, tree, offset); else if ( object_type == 25 ) offset = fEventLogRecord(tvb, pinfo, tree, offset); else if ( object_type == 27 ) offset = fLogMultipleRecord(tvb, pinfo, tree, offset); else offset = fLogRecord(tvb, pinfo, tree, offset); break; case 159: /* member-of */ case 165: /* zone-members */ case 211: /* subordinate-list */ case 246: /* access-doors */ case 249: /* access-event-credential */ case 252: /* accompaniment */ case 265: /* credentials */ case 266: /* credentials-in-zone */ case 277: /* last-credential-added */ case 279: /* last-credential-removed */ case 286: /* members */ case 320: /* zone-from */ case 321: /* zone-to */ case 461: /* energy-meter-ref */ case 491: /* represents */ 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, pinfo, tree, offset); break; case 152: /* active-cov-subscriptions */ offset = fCOVSubscription(tvb, pinfo, tree, offset); break; case 23: /* date-list */ offset = fCalendarEntry(tvb, pinfo, tree, offset); break; case 116: /* time-sychronization-recipients */ case 206: /* utc-time-synchronization-recipients */ case 202: /* restart-notification-recipients */ offset = fRecipient(tvb, pinfo, tree, offset); break; case 83: /* event-parameters */ offset = fEventParameter(tvb, pinfo, tree, offset); break; case 130: /* event-time-stamp */ 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 = fEventTimeStamps(tvb, pinfo, tree, offset); } break; case 197: /* logging-type */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLoggingType); break; case 36: /* event-state */ offset = fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, ar, BACnetEventState, 64); break; case 103: /* reliability */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetReliability); break; case 72: /* notify-type */ offset = fNotifyType(tvb, pinfo, tree, offset); break; case 208: /* node-type */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetNodeType); break; case 231: /* door-status */ case 450: /* car-door-status */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetDoorStatus); break; case 233: /* lock-status */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLockStatus); break; case 235: /* secured-status */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetDoorSecuredStatus); break; case 158: /* maintenance-required */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetMaintenance); break; case 92: /* program-state */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetProgramState); break; case 90: /* program-change */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetProgramRequest); break; case 100: /* reason-for-halt */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetProgramError); break; case 157: /* last-restore-time */ offset = fTimeStamp(tvb, pinfo, tree, offset, ar); break; case 160: /* mode */ case 175: /* accepted-modes */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyMode); break; case 163: /* silenced */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetSilencedState); break; case 161: /* operation-expected */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyOperation); break; case 164: /* tracking-value */ if (object_type == 21 || object_type == 22) /* life-safety-point/zone */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyState); else if (object_type == 63) /* color */ offset = fXyColor(tvb, pinfo, tree, offset, ar); else if (object_type == 64) /* color-temperature */ offset = fUnsignedTag(tvb, pinfo, tree, offset, ar); break; case 166: /* life-safety-alarm-values */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyState); break; case 41: /* file-access-method */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetFileAccessMethod); break; case 185: /* prescale */ offset = fPrescale(tvb, pinfo, tree, offset); break; case 187: /* scale */ offset = fScale(tvb, pinfo, tree, offset); break; case 189: /* update-time */ if (object_type == 37) offset = fTimeStamp(tvb, pinfo, tree, offset, ar); else offset = fDateTime(tvb, pinfo, tree, offset, ar); break; case 184: /* logging-record */ offset = fLoggingRecord(tvb, pinfo, tree, offset); break; case 203: /* time-of-device-restart */ offset = fTimeStamp(tvb, pinfo, tree, offset, ar); break; case 226: /* door-alarm-state */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetDoorAlarmState); break; case 228: /* door-members */ offset = fDoorMembers(tvb, pinfo, tree, offset); break; case 234: /* masked-alarm-values */ offset = fSequenceOfEnums(tvb, pinfo, tree, offset, ar, BACnetDoorAlarmState); break; case 248: /* access-event-authentication-factor */ offset = fAuthenticationFactor(tvb, pinfo, tree, offset); break; case 261: /* authorization-mode */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAuthorizationMode); break; case 53: /* list-of-group-members */ save_object_type = object_type; offset = fListOfGroupMembers(tvb, pinfo, tree, offset); object_type = save_object_type; break; case 296: /* occupancy-state */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAccessZoneOccupancyState); break; case 300: /* passback-mode */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAccessPassbackMode); break; case 303: /* reason-for-disable */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAccessCredentialDisableReason); break; case 318: /* user-type */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAccessUserType); break; case 330: /* key-sets */ offset = fSecurityKeySet(tvb, pinfo, tree, offset); break; case 332: /* network-access-security-policies */ offset = fNetworkSecurityPolicy(tvb, pinfo, tree, offset); break; case 338: /* backup-and-restore-state */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetBackupState); break; case 370: /* write-status */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetWriteStatus); break; case 385: /* transition */ if (object_type == 54) /* lighting-output */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLightingTransition); else if (object_type == 63) /* color */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetColorTransition); else if (object_type == 64) /* color-temperature */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetColorTransition); break; case 288: /* negative-access-rules */ case 302: /* positive-access-rules */ offset = fAccessRule(tvb, pinfo, tree, offset); break; case 304: /* suppoprted-formats */ offset = fAuthenticationFactorFormat(tvb, pinfo, tree, offset); break; case 327: /* base-device-security-policy */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetSecurityLevel); break; case 371: /* property-list */ offset = fSequenceOfEnums(tvb, pinfo, tree, offset, ar, BACnetPropertyIdentifier); break; case 358: /* fault-parameters */ offset = fFaultParameter(tvb, pinfo, tree, offset); break; case 359: /* fault type */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetFaultType); break; case 362: /* subscribed-recipients */ offset = fEventNotificationSubscription(tvb, pinfo, tree, offset); break; case 364: /* authorization-exemptions */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAuthorizationExemption); break; case 378: /* in-progress */ if (object_type == 54) /* lighting-output */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLightingInProgress); else if (object_type == 63) /* color */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetColorOperationInProgress); else if (object_type == 64) /* color-temperature */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetColorOperationInProgress); break; case 380: /* lighting-command */ offset = fLightingCommand(tvb, pinfo, tree, offset, ar); break; case 16: /* change-of-state-time */ case 71: /* modification-date */ case 114: /* time-of-active-time-reset */ case 115: /* time-of-state-count-reset */ case 142: /* start-time */ case 143: /* stop-time */ case 149: /* maximum-value-time-stamp */ case 150: /* minimum-value-time-stamp */ case 179: /* count-change-time */ case 192: /* value-change-time */ case 254: /* activation-time */ case 270: /* expiration-time */ case 278: /* last-credential-added-time */ case 280: /* last-credential-removed-time */ case 281: /* last-use-time */ case 392: /* time-of-strike-count-reset */ offset = fDateTime(tvb, pinfo, tree, offset, ar); break; case 258: /* authentication-policy-list */ offset = fAuthenticationPolicy(tvb, pinfo, tree, offset); break; case 395: /* last-state-change */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetTimerTransition); break; case 396: /* state-change-values */ offset = fTimerStateChangeValue(tvb, pinfo, tree, offset); break; case 398: /* timer-state */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetTimerState); break; case 407: /* bacnet-ip-global-address */ case 418: /* fd-bbmd-address */ offset = fHostNPort(tvb, pinfo, tree, offset, ar); break; case 408: /* bacnet-ip-mode */ case 435: /* bacnet-ipv6-mode */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetIpMode); break; case 414: /* bmd-broadcast-distribution-table */ offset = fBDTEntry(tvb, pinfo, tree, offset, ar); break; case 415: /* bbmd-foreign-device-table */ offset = fFDTEntry(tvb, pinfo, tree, offset, ar); break; case 417: /* command */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetNetworkPortCommand); break; case 426: /* network-number-quality */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetNetworkNumberQuality); break; case 427: /* network-type */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetNetworkType); break; case 428: /* routing-table */ offset = fRouterEntry(tvb, pinfo, tree, offset); break; case 429: /* virtual-mac-address-table */ offset = fVMACEntry(tvb, pinfo, tree, offset); break; case 430: /* command-time-array */ 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 = fTimeStamp(tvb, pinfo, tree, offset, ar); } break; case 432: /* last-command-time */ offset = fTimeStamp(tvb, pinfo, tree, offset, ar); break; case 433: /* value-source */ offset = fValueSource(tvb, pinfo, tree, offset); break; case 434: /* value-source-array */ 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 = fValueSource(tvb, pinfo, tree, offset); } break; case 447: /* assigned-landing-calls */ offset = fAssignedLandingCalls(tvb, pinfo, tree, offset); break; case 448: /* car-assigned-direction */ case 457: /* car-moving-direction */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLiftCarDirection); break; case 449: /* car-door-command */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLiftCarDoorCommand); break; case 453: /* car-drive-status */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLiftCarDriveStatus); break; case 456: /* car-mode */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLiftCarMode); break; case 462: /* escalator-mode */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetEscalatorMode); break; case 463: /* fault-signals */ 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 { if (object_type == 59) /* lift object */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLiftFault); else offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetEscalatorFault); } break; case 467: /* group-mode */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLiftGroupMode); break; case 470: /* landing-calls */ 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 = fLandingCallStatus(tvb, pinfo, tree, offset); } break; case 471: /* landing-call-control */ offset = fLandingCallStatus(tvb, pinfo, tree, offset); break; case 472: /* landing-door-status */ 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 = fLandingDoorStatus(tvb, pinfo, tree, offset); } break; case 477: /* "operation-direction */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetEscalatorOperationDirection); break; case 481: /* active-cov-multiple-subscriptions */ 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 = fCOVMultipleSubscription(tvb, pinfo, tree, offset); } break; case 482: /* protocol-level */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetProtocolLevel); break; case 486: /* tags */ 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 = fNameValue(tvb, pinfo, tree, offset); } break; case 487: /* subordinate-node-types */ 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 = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetNodeType); } break; case 488: /* subordinate-tags */ 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 = fNameValueCollection(tvb, pinfo, tree, offset); } break; case 489: /* subordinate-relationship */ 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 = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetRelationship); } break; case 490: /* default-subordinate-relationship */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetRelationship); break; case 494: /* stages */ 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 = fStageLimitValue(tvb, pinfo, tree, offset); } break; case 498: /* audit-level */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAuditLevel); break; case 500: /* audit-priority-filter */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAuditPriorityFilter); break; case 501: /* auditable-operations */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetAuditOperation); break; case 504: /* monitored-objects */ 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 = fObjectSelector(tvb, pinfo, tree, offset); } break; case 510: /* command-validation-result */ case 4194307: /* current-health */ offset = fHealth(tvb, pinfo, tree, offset); break; case 4194312: /* sc-direct-connect-connection-status */ offset = fSCDirectConnection(tvb, pinfo, tree, offset); break; case 4194315: /* sc-failed-connection-requests */ offset = fSCFailedConnectionRequest(tvb, pinfo, tree, offset); break; case 4194316: /* sc-failover-hub-connection-status */ case 4194324: /* sc-primary-hub-connection-status */ offset = fSCHubConnection(tvb, pinfo, tree, offset); break; case 4194318: /* sc_hub_connector_state */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetSCHubConnectorState); break; case 4194321: /* sc-hub-function-connection-status */ offset = fSCHubFunctionConnection(tvb, pinfo, tree, offset); break; case 4194330: /* default-color */ offset = fXyColor(tvb, pinfo, tree, offset, ar); break; case 4194334: /* color-command */ offset = fColorCommand(tvb, pinfo, tree, offset, ar); break; case 85: /* present-value */ if ( object_type == 11 ) /* group object handling of present-value */ { offset = fReadAccessResult(tvb, pinfo, tree, offset); } else if (object_type == 30) /* access-door object */ { offset = fPresentValue(tvb, pinfo, tree, offset, BACnetDoorValue, 0, BACAPP_PRESENT_VALUE_ENUM); } else if (object_type == 21) /* life-point */ { offset = fPresentValue(tvb, pinfo, tree, offset, BACnetLifeSafetyState, 0, BACAPP_PRESENT_VALUE_ENUM); } else if (object_type == 22) /* life-zone */ { offset = fPresentValue(tvb, pinfo, tree, offset, BACnetLifeSafetyState, 0, BACAPP_PRESENT_VALUE_ENUM); } else if (object_type == 53) /* channel object */ { offset = fChannelValue(tvb, pinfo, tree, offset, ar); } else if (object_type == 37) /* credential-data-input */ { offset = fAuthenticationFactor(tvb, pinfo, tree, offset); } else if (object_type == 26) /* global-group */ { offset = fPropertyAccessResult(tvb, pinfo, tree, offset); } else if (object_type == 28) /* loac-control */ { offset = fPresentValue(tvb, pinfo, tree, offset, BACnetShedState, 0, BACAPP_PRESENT_VALUE_ENUM); } else if (object_type == 43) /* date-time-pattern-value */ { offset = fDateTime(tvb, pinfo, tree, offset, ar); } else if (object_type == 44) /* date-time-value */ { offset = fDateTime(tvb, pinfo, tree, offset, ar); } else if (object_type == 63) /* color */ { offset = fXyColor(tvb, pinfo, tree, offset, ar); } else { if (!tag_info) { fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); // application tag number above 12 reserved for ASHRAE if (!tag_is_context_specific(tag_info) && tag_no <= 12) { offset = fPresentValue(tvb, pinfo, tree, offset, NULL, 0, (BacappPresentValueType) tag_no); } } else { do_default_handling = TRUE; } } break; default: do_default_handling = TRUE; break; } if (do_default_handling) { if (tag_info) { if (tag_is_opening(tag_info)) { ++depth; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else if (tag_is_closing(tag_info)) { --depth; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else { offset = fContextTaggedValue(tvb, pinfo, tree, offset, ar); } } else { offset = fApplicationTypes(tvb, pinfo, tree, offset, ar); } } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } cleanup: recursion_depth = p_get_proto_depth(pinfo, proto_bacapp); p_set_proto_depth(pinfo, proto_bacapp, recursion_depth - 1); return offset; } static guint 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, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, tree, offset); if (tvb_reported_length_remaining(tvb, offset) > 0) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } } else { proto_tree_add_expert(tree, pinfo, &ei_bacapp_opening_tag, tvb, offset, -1); offset = tvb_reported_length(tvb); } return offset; } static guint fPropertyIdentifierValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset) { guint lastoffset = offset; guint8 tag_no, tag_info; guint32 lvt; offset = fPropertyReference(tvb, pinfo, tree, offset, tagoffset, 0); if (offset > lastoffset) { fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_no == tagoffset+2) { /* Value - might not be present in ReadAccessResult */ offset = fPropertyValue(tvb, pinfo, tree, offset, tag_info); } } return offset; } static guint fBACnetPropertyValue(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; offset = fPropertyIdentifierValue(tvb, pinfo, tree, offset, 0); if (offset > lastoffset) { /* detect optional priority by looking to see if the next tag is context tag number 3 */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_context_specific(tag_info) && (tag_no == 3)) offset = fUnsignedTag(tvb, pinfo, tree, offset, "Priority: "); } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fSubscribeCOVPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, 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, pinfo, tree, offset, "subscriber Process Id: "); break; case 1: /* monitored ObjectId */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 2: /* issueConfirmedNotifications */ offset = fBooleanTag(tvb, pinfo, tree, offset, "issue Confirmed Notifications: "); break; case 3: /* life time */ offset = fTimeSpan(tvb, pinfo, tree, offset, "life time"); break; case 4: /* monitoredPropertyIdentifier */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "monitoredPropertyIdentifier"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyReference(tvb, pinfo, subtree, offset, 1); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; case 5: /* covIncrement */ offset = fRealTag(tvb, pinfo, tree, offset, "COV Increment: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fSubscribeCOVPropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; proto_tree *subsubtree = tree; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, 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, pinfo, tree, offset, "subscriber Process Id: "); break; case 1: /* issueConfirmedNotifications */ offset = fBooleanTag(tvb, pinfo, tree, offset, "issue Confirmed Notifications: "); break; case 2: /* life time */ offset = fTimeSpan(tvb, pinfo, tree, offset, "life time"); break; case 3: /* notification delay */ offset = fTimeSpan(tvb, pinfo, tree, offset, "notification delay"); break; case 4: /* list-of-cov-subscription-specifications */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "list-of-cov-subscription-specifications: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += len; subtree = tree; break; } switch (tag_no) { case 0: /* monitored-object-identifier */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 1: /* list-of-cov-references */ if (tag_is_opening(tag_info)) { subsubtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "list-of-cov-references: "); offset += fTagHeaderTree(tvb, pinfo, subsubtree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { fTagHeaderTree(tvb, pinfo, subsubtree, offset, &tag_no, &tag_info, &lvt); offset += len; break; } switch (tag_no) { case 0: /* monitored-property */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subsubtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyReference(tvb, pinfo, subsubtree, offset, 1); offset += fTagHeaderTree(tvb, pinfo, subsubtree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, subsubtree, &ei_bacapp_bad_tag); } break; case 1: /* cov-increment */ offset = fRealTag(tvb, pinfo, subsubtree, offset, "COV Increment: "); break; case 2: /* timestamped */ offset = fBooleanTag(tvb, pinfo, subsubtree, offset, "timestamped: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } } else { expert_add_info(pinfo, subsubtree, &ei_bacapp_bad_tag); } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fSubscribeCOVPropertyMultipleError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); offset += len; break; } switch (tag_no) { case 0: /* normal error */ if (tag_is_opening(tag_info)) { offset = fContextTaggedError(tvb, pinfo, tree, offset); } else { offset = fError(tvb, pinfo, tree, offset); } break; case 1: /* first-failed-subscription */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset += len; break; } switch (tag_no) { case 0: /* monitored-object-identifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 1: /* monitored-property-reference */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyReference(tvb, pinfo, tree, offset, 1); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, tree, &ei_bacapp_bad_tag); } break; case 2: /* error-type */ offset = fContextTaggedError(tvb, pinfo, tree, offset); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fSubscribeCOVRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fSubscribeCOVPropertyRequest(tvb, pinfo, tree, offset); } static guint fWhoHas(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* deviceInstanceLowLimit */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "device Instance Low Limit: "); break; case 1: /* deviceInstanceHighLimit */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "device Instance High Limit: "); break; case 2: /* BACnetObjectId */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 3: /* ObjectName */ offset = fObjectName(tvb, pinfo, tree, offset); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fDailySchedule(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info) && tag_no == 0) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* opening context tag 0 */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { /* should be closing context tag 0 */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset; } offset = fTimeValue(tvb, pinfo, subtree, offset); if (offset <= lastoffset) break; /* nothing happened, exit loop */ } } else if ((tag_no == 0) && (lvt == 0)) { /* not sure null (empty array element) is legal */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } return offset; } /** * BACnetHealth ::= SEQUENCE { * timestamp [0] BACnetDateTime, * result [1] Error, * property [2] BACnetPropertiyIdentifier OPTIONAL, * details [3] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fHealth(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* result */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* property - OPTIONAL*/ offset = fPropertyIdentifier(tvb, pinfo, tree, offset); break; case 3: /* details - OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "details: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } /** * BACnetSCDirectConnection ::= SEQUENCE { * uri [0] CharacterString * connection-state [1] BACnetSCConnectionState, * connect-timestamp [2] BACnetDateTime, * disconnect-timestamp [3] BACnetDateTime, * peer-address [4] BACnetHostNPort, * peer-vmac [5] OCTET STRING (SIZE(6)) * peer-uuid [6] OCTET STRING (SIZE(16)) * error [7] Error OPTIONAL * error-details [8] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fSCDirectConnection(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* uri */ offset = fCharacterString(tvb, pinfo, tree, offset, "uri: "); break; case 1: /* connection-state */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "connection-state: ", BACnetSCConnectionState); break; case 2: /* connect-timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "connet-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 3: /* disconnect-timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "disconnect-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* peer-address */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fHostNPort(tvb, pinfo, tree, offset,"peer-address: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 5: /* peer-vmac */ offset = fOctetString(tvb, pinfo, tree, offset, "peer-vmac: ", lvt); break; case 6: /* peer-uuid */ offset = fOctetString(tvb, pinfo, tree, offset, "peer-uuid: ", lvt); break; case 7: /* error */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 8: /* details - OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "details: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } /** * BACnetSCFailedConnectionRequest ::= SEQUENCE { * timestamp [0] BACnetDateTime, * peer-address [1] BACnetHostNPort, * peer-vmac [2] OCTET STRING (SIZE(6)) * peer-uuid [3] OCTET STRING (SIZE(16)) * error [4] Error OPTIONAL * error-details [5] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fSCFailedConnectionRequest(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "connet-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* peer-address */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fHostNPort(tvb, pinfo, tree, offset,"peer-address: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* peer-vmac */ offset = fOctetString(tvb, pinfo, tree, offset, "peer-vmac: ", lvt); break; case 3: /* peer-uuid */ offset = fOctetString(tvb, pinfo, tree, offset, "peer-uuid: ", lvt); break; case 4: /* error */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 5: /* details - OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "details: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } /** * BACnetSCHubConnection ::= SEQUENCE { * connection-state [0] BACnetSCConnectionState, * connect-timestamp [1] BACnetDateTime, * disconnect-timestamp [2] BACnetDateTime, * error [3] Error OPTIONAL * error-details [4] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fSCHubConnection(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* connection-state */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "connection-state: ", BACnetSCConnectionState); break; case 1: /* connect-timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "connet-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* disconnect-timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "disconnect-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 3: /* error */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* details - OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "details: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } /** * BACnetSCHubFunctionConnection ::= SEQUENCE { * connection-state [0] BACnetSCConnectionState, * connect-timestamp [1] BACnetDateTime, * disconnect-timestamp [2] BACnetDateTime, * peer-address [3] BACnetHostNPort, * peer-vmac [4] OCTET STRING (SIZE(6)) * peer-uuid [5] OCTET STRING (SIZE(16)) * error [6] Error OPTIONAL * error-details [7] CharacterString OPTIONAL * } * @param tvb the tv buffer of the current data * @param pinfo the packet info of the current data * @param tree the tree to append this item to * @param offset the offset in the tvb * @return modified offset */ static guint fSCHubFunctionConnection(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* connection-state */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "connection-state: ", BACnetSCConnectionState); break; case 1: /* connect-timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "connet-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* disconnect-timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "disconnect-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 3: /* peer-address */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fHostNPort(tvb, pinfo, tree, offset,"peer-address: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* peer-vmac */ offset = fOctetString(tvb, pinfo, tree, offset, "peer-vmac: ", lvt); break; case 5: /* peer-uuid */ offset = fOctetString(tvb, pinfo, tree, offset, "peer-uuid: ", lvt); break; case 6: /* error */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 7: /* details - OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "details: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint 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; /* day of week array index */ proto_tree *subtree = tree; 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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; /* outer encoding will print out closing tag */ } subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_bacapp_value, NULL, val_to_str(i++, day_of_week, "day of week (%d) not found")); offset = fDailySchedule(tvb, pinfo, subtree, offset); if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fUTCTimeSynchronizationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; return fDateTime(tvb, pinfo, tree, offset, "UTC-Time: "); } static guint fTimeSynchronizationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; return fDateTime(tvb, pinfo, tree, offset, NULL); } static guint fWriteGroupRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { offset += len; subtree = tree; continue; } switch (tag_no) { case 0: /* group-number */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "Group number: "); break; case 1: /* write-priority */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "Priority: "); break; case 2: /* change-list */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "change-list: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += len; subtree = tree; break; } switch (tag_no) { case 0: /* channel */ if (tag_info && ! tag_is_opening(tag_info)) { /* context tagged */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "Channel: "); } else { /* application tagged */ offset = fChannelValue(tvb, pinfo, subtree, offset, "Value: "); } break; case 1: /* overriding-priority */ if (tag_info && ! tag_is_opening(tag_info)) { /* context tagged */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "Overriding priority: "); } else { /* application tagged */ offset = fChannelValue(tvb, pinfo, subtree, offset, "Value: "); } break; default: /* channel-value (application tagged, or opening/closing context-0 tagged) */ offset = fChannelValue(tvb, pinfo, subtree, offset, "Value: "); break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; case 3: /* inhibit-delay */ offset = fBooleanTag(tvb, pinfo, tree, offset, "Inhibit delay: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fDateRange(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; offset = fDate(tvb, pinfo, tree, offset, "Start Date: "); return fDate(tvb, pinfo, tree, offset, "End Date: "); } static guint 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, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset + tag_len, lvt, &val)) subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, &ti, "%s: %s (%u)", label, val_to_str_ext_const(val, &BACnetVendorIdentifiers_ext, "Unknown Vendor"), val); else subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, &ti, "%s - %u octets (Unsigned)", label, lvt); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); if ((lvt < 1) || (lvt > 2)) { /* vendorIDs >= 1 and <= 2 are supported */ expert_add_info_format(pinfo, ti, &ei_bacapp_bad_length, "Wrong length indicated. Expected 1 or 2, got %u", lvt); return offset+tag_len+lvt; } proto_tree_add_item(subtree, hf_BACnetVendorIdentifier, tvb, offset+tag_len, lvt, ENC_BIG_ENDIAN); 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, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset + tag_len, lvt, &val)) subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, &ti, "%s: %s (%u)", label, val_to_str_const(val, BACnetRestartReason, "Unknown reason"), val); else subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, &ti, "%s - %u octets (Unsigned)", label, lvt); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); if (lvt != 1) { expert_add_info_format(pinfo, ti, &ei_bacapp_bad_length, "Wrong length indicated. Expected 1, got %u", lvt); return offset+tag_len+lvt; } proto_tree_add_item(subtree, hf_BACnetRestartReason, tvb, offset+tag_len, lvt, ENC_BIG_ENDIAN); return offset+tag_len+lvt; } static guint fConfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* textMessageSourceDevice */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); break; case 1: /* messageClass */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: /* numeric */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "message Class: "); break; case 1: /* character */ offset = fCharacterString(tvb, pinfo, tree, offset, "message Class: "); break; } offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* messagePriority */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "message Priority: ", BACnetMessagePriority); break; case 3: /* message */ offset = fCharacterString(tvb, pinfo, tree, offset, "message: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fUnconfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fConfirmedTextMessageRequest(tvb, pinfo, tree, offset); } static guint fConfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; tvbuff_t *next_tvb; guint vendor_identifier = 0; guint service_number = 0; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); fUnsigned32(tvb, offset+len, lvt, &vendor_identifier); col_append_fstr(pinfo->cinfo, COL_INFO, "V=%u ", vendor_identifier); offset = fVendorIdentifier(tvb, pinfo, subtree, offset); next_tvb = tvb_new_subset_remaining(tvb, offset); if (dissector_try_uint(bacapp_dissector_table, vendor_identifier, next_tvb, pinfo, tree)) { /* we parsed it so skip over length and we are done */ offset += tvb_reported_length(next_tvb); return offset; } /* Not handled by vendor dissector */ /* exit loop if nothing happens inside */ while (tvb_reported_length_remaining(tvb, offset) > 0) { lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { if (tag_no == 2) { /* Make sure it's the expected tag */ offset += len; subtree = tree; continue; } else { break; /* End loop if incorrect closing tag */ } } switch (tag_no) { /* vendorID is now parsed above */ case 1: /* serviceNumber */ fUnsigned32(tvb, offset+len, lvt, &service_number); col_append_fstr(pinfo->cinfo, COL_INFO, "SN=%u ", service_number); offset = fUnsignedTag(tvb, pinfo, subtree, offset, "service Number: "); break; case 2: /*serviceParameters */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "service Parameters"); propertyIdentifier = -1; offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset); } static guint fConfirmedPrivateTransferAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset); } static guint fLifeSafetyOperationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; if (label != NULL) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, label); } while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* subscriberProcessId */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "requesting Process Id: "); break; case 1: /* requestingSource */ offset = fCharacterString(tvb, pinfo, tree, offset, "requesting Source: "); break; case 2: /* request */ offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, "request: ", BACnetLifeSafetyOperation, 64); break; case 3: /* objectId */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } typedef struct _value_string_enum { guint8 tag_no; const value_string *valstr; } value_string_enum; static const value_string_enum BACnetPropertyStatesEnums[] = { { 1, BACnetBinaryPV }, { 2, BACnetEventType }, { 3, BACnetPolarity }, { 4, BACnetProgramRequest }, { 5, BACnetProgramState }, { 6, BACnetProgramError }, { 7, BACnetReliability }, { 8, BACnetEventState }, { 9, BACnetDeviceStatus }, { 10, BACnetEngineeringUnits }, { 12, BACnetLifeSafetyMode }, { 13, BACnetLifeSafetyState }, { 14, BACnetRestartReason }, { 15, BACnetDoorAlarmState }, { 16, BACnetAction }, { 17, BACnetDoorSecuredStatus }, { 18, BACnetDoorStatus }, { 19, BACnetDoorValue }, { 20, BACnetFileAccessMethod }, { 21, BACnetLockStatus }, { 22, BACnetLifeSafetyOperation }, { 23, BACnetMaintenance }, { 24, BACnetNodeType }, { 25, BACnetNotifyType }, { 26, BACnetSecurityLevel }, { 27, BACnetShedState }, { 28, BACnetSilencedState }, { 30, BACnetAccessEvent }, { 31, BACnetAccessZoneOccupancyState }, { 32, BACnetAccessCredentialDisableReason }, { 33, BACnetAccessCredentialDisable }, { 34, BACnetAuthenticationStatus }, { 36, BACnetBackupState }, { 37, BACnetWriteStatus }, { 38, BACnetLightingInProgress }, { 39, BACnetLightingOperation }, { 40, BACnetLightingTransition }, { 42, BACnetBinaryLightingPV }, { 43, BACnetTimerState }, { 44, BACnetTimerTransition }, { 45, BACnetIpMode }, { 46, BACnetNetworkPortCommand }, { 47, BACnetNetworkType }, { 48, BACnetNetworkNumberQuality }, { 49, BACnetEscalatorOperationDirection }, { 50, BACnetEscalatorFault }, { 51, BACnetEscalatorMode }, { 52, BACnetLiftCarDirection }, { 53, BACnetLiftCarDoorCommand }, { 54, BACnetLiftCarDriveStatus }, { 55, BACnetLiftCarMode }, { 56, BACnetLiftGroupMode }, { 57, BACnetLiftFault }, { 58, BACnetProtocolLevel }, { 59, BACnetAuditLevel }, { 60, BACnetAuditOperation } }; #define BACnetPropertyStatesEnums_Size \ (sizeof(BACnetPropertyStatesEnums) / sizeof(BACnetPropertyStatesEnums[0])) static guint fBACnetPropertyStates(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint32 idx; const gchar* label; const value_string_enum* valstrenum; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); label = wmem_strdup_printf(pinfo->pool, "%s: ", val_to_str_const( tag_no, VALS(BACnetPropertyStates), "Unknown State" )); switch (tag_no) { case 0: offset = fBooleanTag(tvb, pinfo, tree, offset, label); break; case 11: offset = fUnsignedTag(tvb, pinfo, tree, offset, label); break; case 41: offset = fSignedTag(tvb, pinfo, tree, offset, label); break; case 63: offset = fUnsignedTag(tvb, pinfo, tree, offset, label); break; default: valstrenum = NULL; for (idx = 0; idx < BACnetPropertyStatesEnums_Size; idx++) { valstrenum = &BACnetPropertyStatesEnums[idx]; if (valstrenum->tag_no == tag_no && valstrenum->valstr != NULL) { break; } valstrenum = NULL; } if (valstrenum == NULL) { offset = fEnumeratedTag(tvb, pinfo, tree, offset, label, NULL); /* don't use Abstract type here because it is context tagged and therefore we don't know app type */ } else { offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, label, VALS(valstrenum->valstr), 64); } break; } 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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, 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, "DeviceIdentifier: "); break; case 1: /* objectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 2: /* propertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, tree, offset); break; case 3: /* arrayIndex - OPTIONAL */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "arrayIndex: "); break; case 4: /* value */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, 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 fObjectPropertyReference(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fDeviceObjectPropertyReference(tvb, pinfo, tree, 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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, 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, "ObjectIdentifier: "); break; case 1: /* propertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, tree, offset); break; case 2: /* arrayIndex - OPTIONAL */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "arrayIndex: "); break; case 3: /* deviceIdentifier - OPTIONAL */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fNotificationParameters(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = offset; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; proto_tree *pvtree; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "notification parameters (%d) %s", tag_no, val_to_str_const(tag_no, BACnetEventType, "invalid type")); /* Opening tag for parameter choice */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* change-of-bitstring */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fBitStringTag(tvb, pinfo, subtree, offset, "referenced-bitstring: "); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 1: /* change-of-state */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyStates(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: offset = fBitStringTagVS(tvb, pinfo, 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_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: offset = fBitStringTag(tvb, pinfo, subtree, offset, "changed-bits: "); break; case 1: offset = fRealTag(tvb, pinfo, subtree, offset, "changed-value: "); break; default: break; } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: offset = fBitStringTagVS(tvb, pinfo, 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_reported_length_remaining(tvb, offset) > 0) { /* 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, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: /* "feedback-value: " */ propertyIdentifier = 40; /* FEEDBACK_VALUE */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, 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_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fRealTag(tvb, pinfo, subtree, offset, "reference-value: "); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: offset = fRealTag(tvb, pinfo, subtree, offset, "setpoint-value: "); break; case 3: offset = fRealTag(tvb, pinfo, 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_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fRealTag(tvb, pinfo, subtree, offset, "exceeding-value: "); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: offset = fRealTag(tvb, pinfo, subtree, offset, "deadband: "); break; case 3: offset = fRealTag(tvb, pinfo, subtree, offset, "exceeded-limit: "); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 6: while (tvb_reported_length_remaining(tvb, offset) > 0) { /* 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: /* deprecated (was 'buffer-ready', changed and moved to [10]) */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "DeviceIdentifier: "); /* buffer-device */ break; case 1: offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); /* buffer-object */ break; case 2: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, subtree, offset, "previous-notification: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 3: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, subtree, offset, "current-notification: "); offset += fTagHeaderTree(tvb, pinfo, 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_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "new-state: ", BACnetLifeSafetyState, 256); break; case 1: offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "new-mode: ", BACnetLifeSafetyMode, 256); break; case 2: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 3: offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "operation-expected: ", BACnetLifeSafetyOperation, 64); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 9: /* extended */ while (tvb_reported_length_remaining(tvb, offset) > 0) { lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fVendorIdentifier(tvb, pinfo, subtree, offset); break; case 1: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "extended-event-type: "); break; case 2: /* parameters */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { const guint param_lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyValue(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { offset = fApplicationTypes(tvb, pinfo, subtree, offset, "parameters: "); } if (offset <= param_lastoffset) break; /* nothing happened, exit loop */ } offset += fTagHeaderTree(tvb, pinfo, 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) > 0) { lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* buffer-property */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "previous-notification: "); break; case 2: offset = fUnsignedTag(tvb, pinfo, 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) > 0) { lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "exceeding-value: "); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "exceeded-limit: "); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; /* 12 reserved */ case 13: /* access-event */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "access event: ", BACnetAccessEvent, 512); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "access-event-tag: "); break; case 3: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fTimeStamp(tvb, pinfo, subtree, offset, "access-event-time: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 4: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 5: /* optional authentication-factor */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAuthenticationFactor(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 14: /* double-out-of-range */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fDoubleTag(tvb, pinfo, subtree, offset, "exceeding-value: "); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: offset = fDoubleTag(tvb, pinfo, subtree, offset, "deadband: "); break; case 3: offset = fDoubleTag(tvb, pinfo, subtree, offset, "exceeded-limit: "); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 15: /* signed-out-of-range */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fSignedTag(tvb, pinfo, subtree, offset, "exceeding-value: "); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "deadband: "); break; case 3: offset = fSignedTag(tvb, pinfo, subtree, offset, "exceeded-limit: "); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 16: /* unsigned-out-of-range */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "exceeding-value: "); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "deadband: "); break; case 3: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "exceeded-limit: "); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 17: /* change-of-characterstring */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* changed-value (CharacterString) */ offset = fCharacterString(tvb, pinfo, subtree, offset, "changed-value: "); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: /* alarm-value (CharacterString) */ offset = fCharacterString(tvb, pinfo, subtree, offset, "alarm-value: "); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 18: /* change-of-status-flags */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_context_specific(tag_info)) { propertyIdentifier = 85; /* suppose present-value here */ offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset); } else { offset = fPresentValue(tvb, pinfo, tree, offset, BACnetStatusFlags, 0, BACAPP_PRESENT_VALUE_ENUM); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "referenced-flags: ", BACnetStatusFlags); lastoffset = offset; break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 19: /* change-of-reliability */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fEnumeratedTag(tvb, pinfo, subtree, offset, "reliability:", BACnetReliability); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: /* property-values */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset; } pvtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "property-values"); offset += fTagHeaderTree(tvb, pinfo, pvtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyValue(tvb, pinfo, pvtree, offset); offset += fTagHeaderTree(tvb, pinfo, pvtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 20: /* context tag [20] is not used */ break; case 21: /* change-of-discrete-value */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* new-value */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, subtree, offset, "new-value: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { offset = fApplicationTypes(tvb, pinfo, subtree, offset, "new-value: "); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* status-flags */ offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 22: /* change-of-timer */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* new-state */ offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "new-state: ", BACnetTimerState, 256); break; case 1: /* status-flags */ offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "status-flags: ", BACnetStatusFlags); break; case 2: /* update-time */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, subtree, offset, "update-time: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 3: /* last-state-change (OPTIONAL) */ offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "new-state: ", BACnetTimerTransition, 256); break; case 4: /* initial-timeout (OPTIONAL) */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "initial-timeout: "); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; /* todo: add new parameters here ... */ default: offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset); break; } /* Closing tag for parameter choice */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset; } static guint fEventParameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = offset; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "event parameters (%d) %s", tag_no, val_to_str_const(tag_no, BACnetEventType, "invalid type")); /* Opening tag for parameter choice */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* change-of-bitstring */ while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: offset = fTimeSpan(tvb, pinfo, subtree, offset, "Time Delay"); break; case 1: offset = fBitStringTag(tvb, pinfo, subtree, offset, "bitmask: "); break; case 2: /* SEQUENCE OF BIT STRING */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fBitStringTag(tvb, pinfo, subtree, offset, "bitstring value: "); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 1: /* change-of-state */ while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: offset = fTimeSpan(tvb, pinfo, subtree, offset, "Time Delay"); break; case 1: /* SEQUENCE OF BACnetPropertyStates */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fBACnetPropertyStates(tvb, pinfo, subtree, offset); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; 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, pinfo, subtree, offset, "Time Delay"); break; case 1: /* don't loop it, it's a CHOICE */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: offset = fBitStringTag(tvb, pinfo, subtree, offset, "bitmask: "); break; case 1: offset = fRealTag(tvb, pinfo, subtree, offset, "referenced Property Increment: "); break; default: break; } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 3: /* command-failure */ while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; tag_no = fTagNo(tvb, offset); switch (tag_no) { case 0: offset = fTimeSpan(tvb, pinfo, subtree, offset, "Time Delay"); break; case 1: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 4: /* floating-limit */ while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: offset = fTimeSpan(tvb, pinfo, subtree, offset, "Time Delay"); break; case 1: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: offset = fRealTag(tvb, pinfo, subtree, offset, "low diff limit: "); break; case 3: offset = fRealTag(tvb, pinfo, subtree, offset, "high diff limit: "); break; case 4: offset = fRealTag(tvb, pinfo, subtree, offset, "deadband: "); break; default: break; } } break; case 5: /* out-of-range */ 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, pinfo, subtree, offset, "Time Delay"); break; case 1: offset = fRealTag(tvb, pinfo, subtree, offset, "low limit: "); break; case 2: offset = fRealTag(tvb, pinfo, subtree, offset, "high limit: "); break; case 3: offset = fRealTag(tvb, pinfo, subtree, offset, "deadband: "); break; default: break; } } break; case 6: /* complex-event-type */ /* deprecated */ offset = fBACnetPropertyValue (tvb, pinfo, tree, offset); break; case 7: /* buffer-ready */ /* deprecated */ while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fUnsignedTag(tvb, pinfo, tree, offset, "notification threshold"); break; case 1: offset = fUnsignedTag(tvb, pinfo, tree, offset, "previous notification count: "); break; default: return offset; } } break; case 8: /* change-of-life-safety */ 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, pinfo, subtree, offset, "Time Delay"); break; case 1: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "life safety alarm value: ", BACnetLifeSafetyState, 256); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "alarm value: ", BACnetLifeSafetyState, 256); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 3: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 9: /* extended */ 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 = fVendorIdentifier(tvb, pinfo, tree, offset); break; case 1: offset = fUnsignedTag(tvb, pinfo, tree, offset, "extended-event-type: "); break; case 2: /* parameters */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info) && tag_no == 2) { break; } if ( ! tag_is_context_specific(tag_info)) { offset = fApplicationTypes(tvb, pinfo, tree, offset, "parameters: "); } else { if (tag_no == 0) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else { offset = fAbstractSyntaxNType(tvb, pinfo, tree, offset); } } } offset += fTagHeaderTree(tvb, pinfo, tree, 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) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "notification-threshold: "); break; case 1: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "previous-notification-count: "); break; default: break; } } break; case 11: /* unsigned-range */ 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, pinfo, tree, offset, "Time Delay"); break; case 1: offset = fUnsignedTag(tvb, pinfo, tree, offset, "low-limit: "); break; case 2: offset = fUnsignedTag(tvb, pinfo, tree, offset, "high-limit: "); break; default: break; } } break; case 13: /* access-event */ while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* TODO: [0] SEQUENCE OF BACnetAccessEvent */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fEnumeratedTagSplit(tvb, pinfo, subtree, offset, "access event: ", BACnetAccessEvent, 512); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 14: /* double-out-of-range */ 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, pinfo, subtree, offset, "Time Delay"); break; case 1: offset = fDoubleTag(tvb, pinfo, subtree, offset, "low limit: "); break; case 2: offset = fDoubleTag(tvb, pinfo, subtree, offset, "high limit: "); break; case 3: offset = fDoubleTag(tvb, pinfo, subtree, offset, "deadband: "); break; default: break; } } break; case 15: /* signed-out-of-range */ 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, pinfo, subtree, offset, "Time Delay"); break; case 1: offset = fSignedTag(tvb, pinfo, subtree, offset, "low limit: "); break; case 2: offset = fSignedTag(tvb, pinfo, subtree, offset, "high limit: "); break; case 3: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "deadband: "); break; default: break; } } break; case 16: /* unsigned-out-of-range */ 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, pinfo, subtree, offset, "Time Delay"); break; case 1: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "low limit: "); break; case 2: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "high limit: "); break; case 3: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "deadband: "); break; default: break; } } break; case 17: /* change-of-characterstring */ 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, pinfo, subtree, offset, "Time Delay"); break; case 1: /* SEQUENCE OF CharacterString */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fCharacterString(tvb, pinfo, tree, offset, "alarm value: "); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 18: /* change-of-status-flags */ 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, pinfo, subtree, offset, "Time Delay"); break; case 1: offset = fBitStringTagVS(tvb, pinfo, subtree, offset, "selected flags: ", BACnetStatusFlags); break; default: break; } } break; case 19: /* has been intentionally omitted. It parallels the change-of-reliability event type */ break; case 20: /* none */ /* no closing tag expected only context tag here */ return offset; case 21: /* change-of-discrete-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, pinfo, subtree, offset, "Time Delay"); break; default: break; } } break; case 22: /* change-of-timer */ while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* time-delay */ offset = fTimeSpan(tvb, pinfo, subtree, offset, "Time Delay"); break; case 1: /* alarm-values */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fEnumeratedTag(tvb, pinfo, subtree, offset, "alarm value: ", BACnetTimerState); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* update-time-reference */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; /* todo: add new event-parameter cases here */ default: break; } /* Closing tag for parameter choice */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset; } static guint fFaultParameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = offset; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "fault parameters (%d) %s", tag_no, val_to_str_const(tag_no, BACnetFaultType, "invalid type")); /* Opening tag for parameter choice */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* none */ /* no closing tag expected only context tag here */ return offset; case 1: /* fault-characterstring */ while ((tvb_reported_length_remaining(tvb, offset) > 0) && (offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* SEQUENCE OF CharacterString */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0) && (offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fCharacterString(tvb, pinfo, subtree, offset, "fault value: "); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 2: /* fault-extended */ 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 = fVendorIdentifier(tvb, pinfo, subtree, offset); break; case 1: offset = fUnsignedTag(tvb, pinfo, subtree, offset, "extended-fault-type: "); break; case 2: /* parameters */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fApplicationTypes(tvb, pinfo, subtree, offset, "parameters: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); lastoffset = offset; break; default: break; } } break; case 3: /* fault-life-safety */ 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 += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0) && (offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fEnumeratedTag(tvb, pinfo, subtree, offset, "fault value: ", BACnetLifeSafetyState); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 4: /* fault-state */ while ((tvb_reported_length_remaining(tvb, offset) > 0) && (offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* SEQUENCE OF BACnetPropertyStates */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0) && (offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fBACnetPropertyStates(tvb, pinfo, subtree, offset); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 5: /* fault-status-flags */ 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 += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 6: /* fault-out-of-range */ while ((tvb_reported_length_remaining(tvb, offset) > 0) && (offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (fTagNo(tvb, offset)) { case 0: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fApplicationTypes(tvb, pinfo, subtree, offset, "min-normal-value: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fApplicationTypes(tvb, pinfo, subtree, offset, "max-normal-value: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; case 7: /* fault-listed */ 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 += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectPropertyReference(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: break; } } break; default: break; } /* Closing tag for parameter choice */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset; } static guint fEventNotificationSubscription(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree; guint itemno = 1; while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* recipient */ tree = proto_tree_add_subtree_format(tree, tvb, offset, 1, ett_bacapp_value, NULL, "Subscription %d", itemno); /* add tree label and indent */ itemno = itemno + 1; subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "Recipient: "); /* add tree label and indent */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fRecipient(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; case 1: /* process-identifier */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Process Identifier: "); break; case 2: /* issue-confirmed-notifications */ offset = fBooleanTag(tvb, pinfo, tree, offset, "Issue Confirmed Notifications: "); break; case 3: /* time-remaining */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Time Remaining: "); break; default: return offset; } } return offset; } static guint fLightingCommand(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *lable) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "%s", lable); while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* operation */ offset = fEnumeratedTag(tvb, pinfo, subtree, offset, "operation: ", BACnetLightingOperation); break; case 1: /* target-level */ offset = fRealTag(tvb, pinfo, subtree, offset, "target-level: "); break; case 2: /* ramp-rate */ offset = fRealTag(tvb, pinfo, subtree, offset, "ramp-rate: "); break; case 3: /* step-increment */ offset = fRealTag(tvb, pinfo, subtree, offset, "step-increment: "); break; case 4: /* fade-time */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "fade-time: "); break; case 5: /* priority */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "priority: "); break; default: return offset; } } return offset; } static guint fColorCommand(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, guint offset, const gchar* lable) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree* subtree = tree; subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "%s", lable); while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* operation */ offset = fEnumeratedTag(tvb, pinfo, subtree, offset, "operation: ", BACnetColorOperation); break; case 1: /* target-color */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fXyColor(tvb, pinfo, subtree, offset, "xy-color: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* target-color-temperature */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "target-color-temperature: "); break; case 3: /* fade-time */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "fade-time: "); break; case 4: /* ramp-rate */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "ramp-rate: "); break; case 5: /* step-increment */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "step-increment: "); break; default: return offset; } } return offset; } static guint fXyColor(tvbuff_t* tvb, packet_info* pinfo, proto_tree* tree, guint offset, const gchar* label) { proto_tree* subtree = tree; if (label != NULL) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 10, ett_bacapp_value, NULL, label); } offset = fRealTag(tvb, pinfo, subtree, offset, "x-coordinate: "); return fRealTag(tvb, pinfo, subtree, offset, "y-coordinate: "); } static guint fTimerStateChangeValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; guint ftag_offset; while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ ftag_offset = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } if (tag_is_context_specific(tag_info)){ switch (tag_no) { case 0: /* no-value */ offset = fNullTag(tvb, pinfo, tree, offset, "no-value: "); break; case 1: /* constructed-value */ offset += ftag_offset; offset = fAbstractSyntaxNType(tvb, pinfo, tree, offset); offset += fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); break; case 2: /* date-time */ offset += ftag_offset; offset = fDateTime(tvb, pinfo, tree, offset, "date-time: "); offset += fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); break; case 3: /* lighting-command */ offset += ftag_offset; offset = fLightingCommand(tvb, pinfo, tree, offset, "lighting-command: "); offset += fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } } else { offset = fApplicationTypes(tvb, pinfo, tree, offset, NULL); } } return offset; } static guint fHostAddress(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; if (tvb_reported_length_remaining(tvb, offset) > 0) { fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* none */ offset = fNullTag(tvb, pinfo, tree, offset, "no-value: "); break; case 1: /* ip-address */ offset = fOctetString(tvb, pinfo, tree, offset, "ip-address: ", lvt); break; case 2: /* internet name (see RFC 1123) */ offset = fCharacterString(tvb, pinfo, tree, offset, "name: "); break; default: return offset; } } return offset; } static guint fHostNPort(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *lable) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "%s", lable); while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* host */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fHostAddress(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* port */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "port: "); break; default: return offset; } } return offset; } static guint fBDTEntry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *lable) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "%s", lable); while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* bbmd-address */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fHostNPort(tvb, pinfo, subtree, offset, "bbmd-address: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* bbmd-mask */ offset = fOctetString(tvb, pinfo, subtree, offset, "bbmd-mask: ", lvt); break; default: return offset; } } return offset; } static guint fFDTEntry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *lable) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "%s", lable); while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* bacnetip-address */ offset = fOctetString(tvb, pinfo, subtree, offset, "bacnetip-address: ", lvt); break; case 1: /* time-to-live */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "time-to-live: "); break; case 2: /* remaining-time-to-live */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "remaining-time-to-live: "); break; default: return offset; } } return offset; } static guint fRouterEntry(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* network number */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "network number: "); break; case 1: /* MAC address */ offset = fOctetString(tvb, pinfo, tree, offset, "MAC address: ", lvt); break; case 2: /* status */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "status: ", BACnetRouterStatus); break; case 3: /* performance index */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "performance index: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fVMACEntry(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* virtual mac address */ offset = fOctetString(tvb, pinfo, tree, offset, "virtual MAC address: ", lvt); break; case 1: /* native mac address */ offset = fOctetString(tvb, pinfo, tree, offset, "native MAC address: ", lvt); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fValueSource(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; if (tvb_reported_length_remaining(tvb, offset) > 0) { fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* null */ offset = fNullTag(tvb, pinfo, tree, offset, "no-value: "); break; case 1: /* object reference */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDeviceObjectReference(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* address */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fAddress(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } } return offset; } static guint fAssignedLandingCalls(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* floor number */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "floor number: "); break; case 1: /* direction */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "direction: ", BACnetLiftCarDirection); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); return offset; } static guint fLandingCallStatus(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* floor number */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "floor number: "); break; case 1: /* direction */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "direction: ", BACnetLiftCarDirection); break; case 2: /* destination */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "destination: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fLandingDoorStatus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* floor number */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "floor number: "); break; case 1: /* door status */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "door status: ", BACnetDoorStatus); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); return offset; } static guint fCOVMultipleSubscription(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* recipient */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fRecipientProcess(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* issue-confirmed-notifications */ offset = fBooleanTag(tvb, pinfo, tree, offset, "issue confirmed notifications: "); break; case 2: /* time-remaining */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "time remaining: "); break; case 3: /* max-notification-delay */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "max notification delay: "); break; case 4: /* list-of-cov-subscription-specifications */ while (tvb_reported_length_remaining(tvb, offset) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* monitored-object-identifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 1: /* list-of-cov-references */ while (tvb_reported_length_remaining(tvb, offset) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* monitored-property */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyReference(tvb, pinfo, tree, offset, 0); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* cov-increment */ offset = fRealTag(tvb, pinfo, tree, offset, "cov-increment: "); break; case 2: /* timestamped */ offset = fBooleanTag(tvb, pinfo, tree, offset, "timestamped: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fNameValue(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) > 0) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } if (tag_is_context_specific(tag_info)) { switch (tag_no) { case 0: /* name */ offset = fCharacterString(tvb, pinfo, tree, offset, "name: "); break; case 1: /* date+time value */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "value: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: /* abstract syntax and type */ /* DMR Should be fAbstractNSyntax, but that's where we came from! */ offset = fApplicationTypes(tvb, pinfo, tree, offset, "value: "); break; } } else { /* DMR Should be fAbstractNSyntax, but that's where we came from! */ offset = fApplicationTypes(tvb, pinfo, tree, offset, "value: "); } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fNameValueCollection(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; subtree = proto_tree_add_subtree_format(subtree, tvb, offset, 0, ett_bacapp_value, NULL, "%s", "name-value-collection: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } offset = fNameValue(tvb, pinfo, subtree, offset); } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); return offset; } static guint fObjectSelector(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* NULL */ offset = fNullTag(tvb, pinfo, tree, offset, "NULL: "); break; case 9: /* object-type */ offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, "object-type: ", BACnetObjectType, 256); break; case 12: /* object */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fStageLimitValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; offset = fRealTag(tvb, pinfo, tree, offset, "limit: "); if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; offset = fBitStringTag(tvb, pinfo, tree, offset, "values: "); if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; offset = fRealTag(tvb, pinfo, tree, offset, "deadband: "); return offset; } static guint fLifeSafetyInfo(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* requesting-process-identifier */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "requesting-process-identifier: "); break; case 1: /* request */ offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, "requested-operation: ", BACnetLifeSafetyOperation, 64); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAcknowledgeAlarmInfo(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* event-state-acknowledged */ offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, "event-state-acknowledged: ", BACnetEventState, 64); break; case 1: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fTimeStamp(tvb, pinfo, tree, offset, "source-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuditNotificationInfo(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint len, lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; guint32 operation = 0; proto_tree *subtree = tree; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* source-timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fTimeStamp(tvb, pinfo, tree, offset, "source-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; case 1: /* target-timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fTimeStamp(tvb, pinfo, tree, offset, "target-timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; case 2: /* source-device */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "source-device: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fRecipient(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; case 3: /* source-object */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "source-object: "); offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 4: /* operation */ fUnsigned32(tvb, offset, lvt, &operation); offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, "operation: ", BACnetAuditOperation, 64); break; case 5: /* source-comment */ offset = fCharacterString(tvb, pinfo, tree, offset, "source-comment: "); break; case 6: /* target-comment */ offset = fCharacterString(tvb, pinfo, tree, offset, "target-comment: "); break; case 7: /* invoke-id */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "invoke-id: "); break; case 8: /* source-user-id */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "source-user-id: "); break; case 9: /* source-user-role */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "source-user-role: "); break; case 10: /* target-device */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "target-device: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fRecipient(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; case 11: /* target-object */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "target-object: "); offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 12: /* target-property */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "target-property: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fPropertyReference(tvb, pinfo, subtree, offset, 0, 0); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; case 13: /* target-priority */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "target-priority: "); break; case 14: /* target-value */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "target-value: "); if (operation == 4) { /* operation life safety */ /* inspect next tag */ fTagHeader(tvb, pinfo, offset + len, &tag_no, &tag_info, &lvt); if ( tag_no == 0 && ! tag_is_opening(tag_info) && tag_is_context_specific(tag_info) ) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fLifeSafetyInfo(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context close */ } else { /* abstract syntax and type */ offset = fPropertyValue(tvb, pinfo, subtree, offset, tag_info); } } else if ( operation == 5 ) { /* operation acknowledge alarm */ /* inspect next tag */ fTagHeader(tvb, pinfo, offset + len, &tag_no, &tag_info, &lvt); if ( tag_no == 0 && ! tag_is_opening(tag_info) && tag_is_context_specific(tag_info) ) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fAcknowledgeAlarmInfo(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context close */ } else { /* abstract syntax and type */ offset = fPropertyValue(tvb, pinfo, subtree, offset, tag_info); } } else { /* abstract syntax and type */ offset = fPropertyValue(tvb, pinfo, subtree, offset, tag_info); } break; case 15: /* current-value */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "current-value: "); /* always abstract syntax and type */ offset = fPropertyValue(tvb, pinfo, subtree, offset, tag_info); break; case 16: /* error-result */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "error-result: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */ offset = fError(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* show context close */ break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuditLogRecord(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; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDate(tvb, pinfo, tree, offset, "Date: "); offset = fTime(tvb, pinfo, tree, offset, "Time: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* logDatum: don't loop, it's a CHOICE */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: /* logStatus */ /* Changed this to BitString per BACnet Spec. */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "log status:", BACnetLogStatus); break; case 1: /* notification */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "notification: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAuditNotificationInfo(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* time-change */ offset = fRealTag(tvb, pinfo, tree, offset, "time-change: "); break; default: return offset; } offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fEventLogRecord(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; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDate(tvb, pinfo, tree, offset, "Date: "); offset = fTime(tvb, pinfo, tree, offset, "Time: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* logDatum: don't loop, it's a CHOICE */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: /* logStatus */ /* Changed this to BitString per BACnet Spec. */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "log status:", BACnetLogStatus); break; case 1: /* notification */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "notification: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fConfirmedEventNotificationRequest(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* time-change */ offset = fRealTag(tvb, pinfo, tree, offset, "time-change: "); break; default: return offset; } offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fLogRecord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; gint32 save_propertyIdentifier; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDate(tvb, pinfo, tree, offset, "Date: "); offset = fTime(tvb, pinfo, tree, offset, "Time: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* logDatum: don't loop, it's a CHOICE */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: /* logStatus */ /* Changed this to BitString per BACnet Spec. */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "log status: ", BACnetLogStatus); break; case 1: offset = fBooleanTag(tvb, pinfo, tree, offset, "boolean-value: "); break; case 2: offset = fRealTag(tvb, pinfo, tree, offset, "real value: "); break; case 3: offset = fUnsignedTag(tvb, pinfo, tree, offset, "enum value: "); break; case 4: offset = fUnsignedTag(tvb, pinfo, tree, offset, "unsigned value: "); break; case 5: offset = fSignedTag(tvb, pinfo, tree, offset, "signed value: "); break; case 6: offset = fBitStringTag(tvb, pinfo, tree, offset, "bitstring value: "); break; case 7: offset = fNullTag(tvb, pinfo, tree, offset, "null value: "); break; case 8: offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 9: offset = fRealTag(tvb, pinfo, tree, offset, "time change: "); break; case 10: /* any Value */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* this ASN-1 construction may contain also an property identifier, so save the one we have got and restore it later and invalidate current one to avoid misinterpretations */ save_propertyIdentifier = propertyIdentifier; propertyIdentifier = -1; offset = fAbstractSyntaxNType(tvb, pinfo, tree, offset); propertyIdentifier = save_propertyIdentifier; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* Changed this to BitString per BACnet Spec. */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "Status Flags: ", BACnetStatusFlags); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fLogMultipleRecord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; gint32 save_propertyIdentifier; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDate(tvb, pinfo, tree, offset, "Date: "); offset = fTime(tvb, pinfo, tree, offset, "Time: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* logData: don't loop, it's a CHOICE */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); switch (fTagNo(tvb, offset)) { case 0: /* logStatus */ /* Changed this to BitString per BACnet Spec. */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "log status: ", BACnetLogStatus); break; case 1: /* log-data: SEQUENCE OF CHOICE */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); while ((tvb_reported_length_remaining(tvb, offset) > 0) && (offset != lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { lastoffset = offset; break; } switch (tag_no) { case 0: offset = fBooleanTag(tvb, pinfo, tree, offset, "boolean-value: "); break; case 1: offset = fRealTag(tvb, pinfo, tree, offset, "real value: "); break; case 2: offset = fUnsignedTag(tvb, pinfo, tree, offset, "enum value: "); break; case 3: offset = fUnsignedTag(tvb, pinfo, tree, offset, "unsigned value: "); break; case 4: offset = fSignedTag(tvb, pinfo, tree, offset, "signed value: "); break; case 5: offset = fBitStringTag(tvb, pinfo, tree, offset, "bitstring value: "); break; case 6: offset = fNullTag(tvb, pinfo, tree, offset, "null value: "); break; case 7: offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 8: /* any Value */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); /* this ASN-1 construction may contain also an property identifier, so save the one we have got and restore it later and invalidate current one to avoid misinterpretations */ save_propertyIdentifier = propertyIdentifier; propertyIdentifier = -1; offset = fAbstractSyntaxNType(tvb, pinfo, tree, offset); propertyIdentifier = save_propertyIdentifier; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } } offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: offset = fRealTag(tvb, pinfo, tree, offset, "time-change: "); break; default: return offset; } offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fConfirmedEventNotificationRequest(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* ProcessId */ offset = fProcessId(tvb, pinfo, tree, offset); break; case 1: /* initiating ObjectId */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 2: /* event ObjectId */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 3: /* time stamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fTimeStamp(tvb, pinfo, tree, offset, NULL); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* notificationClass */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Notification Class: "); break; case 5: /* Priority */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Priority: "); break; case 6: /* EventType */ offset = fEventType(tvb, pinfo, tree, offset); break; case 7: /* messageText */ offset = fCharacterString(tvb, pinfo, tree, offset, "message Text: "); break; case 8: /* NotifyType */ offset = fNotifyType(tvb, pinfo, tree, offset); break; case 9: /* ackRequired */ offset = fBooleanTag(tvb, pinfo, tree, offset, "ack Required: "); break; case 10: /* fromState */ offset = fFromState(tvb, pinfo, tree, offset); break; case 11: /* toState */ offset = fToState(tvb, pinfo, tree, offset); break; case 12: /* NotificationParameters */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fNotificationParameters(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, 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, packet_info *pinfo, proto_tree *tree, guint offset) { return fConfirmedEventNotificationRequest(tvb, pinfo, tree, offset); } static guint fConfirmedCOVNotificationMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; proto_tree *subsubtree = tree; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, 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, pinfo, tree, offset); break; case 1: /* initiating DeviceId */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); break; case 2: /* time remaining */ offset = fTimeSpan(tvb, pinfo, tree, offset, "Time remaining: "); break; case 3: /* timestamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, tree, offset, "Timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* list-of-cov-notifications */ if (tag_is_opening(tag_info)) { /* new subtree for list-of-cov-notifications */ subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "list-of-cov-notifications: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { /* end for list-of-cov-notifications */ fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += len; subtree = tree; break; } switch (tag_no) { case 0: /* monitored-object-identifier */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 1: /* list-of-values */ if (tag_is_opening(tag_info)) { /* new subtree for list-of-values */ subsubtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "list-of-values: "); offset += fTagHeaderTree(tvb, pinfo, subsubtree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { /* end of list-of-values */ fTagHeaderTree(tvb, pinfo, subsubtree, offset, &tag_no, &tag_info, &lvt); offset += len; break; } switch (tag_no) { case 0: /* PropertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, subsubtree, offset); break; case 1: /* propertyArrayIndex */ offset = fPropertyArrayIndex(tvb, pinfo, subsubtree, offset); break; case 2: /* property-value */ offset = fPropertyValue(tvb, pinfo, subsubtree, offset, tag_info); break; case 3: /* time-of-change */ offset = fTime(tvb, pinfo, subsubtree, offset, "time of change: "); break; default: /* wrong tag encoding */ return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } } else { /* wrong tag encoding */ expert_add_info(pinfo, subsubtree, &ei_bacapp_bad_tag); } break; default: /* wrong tag encoding */ return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } } else { /* wrong tag encoding */ expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: /* wrong tag encoding */ return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fUnconfirmedCOVNotificationMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fConfirmedCOVNotificationMultipleRequest(tvb, pinfo, tree, offset); } static guint fConfirmedCOVNotificationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += len; subtree = tree; continue; } switch (tag_no) { case 0: /* ProcessId */ offset = fProcessId(tvb, pinfo, tree, offset); break; case 1: /* initiating DeviceId */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "DeviceIdentifier: "); break; case 2: /* monitored ObjectId */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 3: /* time remaining */ offset = fTimeSpan(tvb, pinfo, tree, offset, "Time remaining: "); break; case 4: /* List of Values */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "list of Values: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyValue(tvb, pinfo, subtree, offset); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fUnconfirmedCOVNotificationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fConfirmedCOVNotificationRequest(tvb, pinfo, tree, offset); } static guint 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_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* acknowledgingProcessId */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "acknowledging Process Id: "); break; case 1: /* eventObjectId */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 2: /* eventStateAcknowledged */ offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, "event State Acknowledged: ", BACnetEventState, 64); break; case 3: /* timeStamp */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fTimeStamp(tvb, pinfo, tree, offset, NULL); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* acknowledgementSource */ offset = fCharacterString(tvb, pinfo, tree, offset, "acknowledgement Source: "); break; case 5: /* timeOfAcknowledgement */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fTimeStamp(tvb, pinfo, tree, offset, "acknowledgement timestamp: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fGetAlarmSummaryAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; offset = fApplicationTypes(tvb, pinfo, tree, offset, "Object Identifier: "); offset = fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, "alarm State: ", BACnetEventState, 64); 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, 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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* acknowledgmentFilter */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "acknowledgment Filter: ", BACnetAcknowledgementFilter); break; case 1: /* eventObjectId - OPTIONAL */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fRecipientProcess(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* eventStateFilter */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "event State Filter: ", BACnetEventStateFilter); break; case 3: /* eventTypeFilter - OPTIONAL */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "event Type Filter: ", BACnetEventType); break; case 4: /* priorityFilter */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fUnsignedTag(tvb, pinfo, tree, offset, "min Priority: "); offset = fUnsignedTag(tvb, pinfo, tree, offset, "max Priority: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 5: /* notificationClassFilter - OPTIONAL */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "notification Class Filter: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fGetEnrollmentSummaryAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; offset = fApplicationTypes(tvb, pinfo, tree, offset, "Object Identifier: "); offset = fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, "event Type: ", BACnetEventType, 64); offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, "event State: ", BACnetEventState); offset = fApplicationTypes(tvb, pinfo, tree, offset, "Priority: "); if (tvb_reported_length_remaining(tvb, offset) > 0 && fTagNo(tvb, offset) == 2) /* Notification Class - OPTIONAL */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "Notification Class: "); if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fGetEventInformationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { if (tvb_reported_length_remaining(tvb, offset) > 0) { if (fTagNo(tvb, offset) == 0) { offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); } } return offset; } static guint 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; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, 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, pinfo, tree, offset, "ObjectIdentifier: "); break; case 1: /* eventState */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "event State: ", BACnetEventState); break; case 2: /* acknowledgedTransitions */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "acknowledged Transitions: ", BACnetEventTransitionBits); break; case 3: /* eventTimeStamps */ subtree = proto_tree_add_subtree(tree, tvb, offset, lvt, ett_bacapp_tag, NULL, "eventTimeStamps"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fTimeStamp(tvb, pinfo, subtree, offset, "TO-OFFNORMAL timestamp: "); offset = fTimeStamp(tvb, pinfo, subtree, offset, "TO-FAULT timestamp: "); offset = fTimeStamp(tvb, pinfo, subtree, offset, "TO-NORMAL timestamp: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 4: /* notifyType */ offset = fNotifyType(tvb, pinfo, tree, offset); break; case 5: /* eventEnable */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "event Enable: ", BACnetEventTransitionBits); break; case 6: /* eventPriorities */ subtree = proto_tree_add_subtree(tree, tvb, offset, lvt, ett_bacapp_tag, NULL, "eventPriorities"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fUnsignedTag(tvb, pinfo, subtree, offset, "TO-OFFNORMAL Priority: "); offset = fUnsignedTag(tvb, pinfo, subtree, offset, "TO-FAULT Priority: "); offset = fUnsignedTag(tvb, pinfo, subtree, offset, "TO-NORMAL Priority: "); offset += fTagHeaderTree(tvb, pinfo, 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, COL_INFO, FALSE); /* don't set all infos into INFO column */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, 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, 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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* listOfEventSummaries */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = flistOfEventSummaries(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* moreEvents */ offset = fBooleanTag(tvb, pinfo, tree, offset, "more Events: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAddListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; col_set_writable(pinfo->cinfo, COL_INFO, FALSE); /* don't set all infos into INFO column */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { offset += len; subtree = tree; continue; } switch (tag_no) { case 0: /* ObjectId */ offset = fBACnetObjectPropertyReference(tvb, pinfo, subtree, offset); break; case 3: /* listOfElements */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "listOfElements"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fDeleteObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); } static guint fDeviceCommunicationControlRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* timeDuration */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "time Duration: "); break; case 1: /* enable-disable */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "enable-disable: ", BACnetEnableDisable); break; case 2: /* password - OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "Password: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fReinitializeDeviceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* reinitializedStateOfDevice */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "reinitialized State Of Device: ", BACnetReinitializedStateOfDevice); break; case 1: /* password - OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "Password: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fVtOpenRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, "vtClass: ", BACnetVTClass); return fApplicationTypes(tvb, pinfo, tree, offset, "local VT Session ID: "); } static guint fVtOpenAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fApplicationTypes(tvb, pinfo, tree, offset, "remote VT Session ID: "); } static guint fVtCloseRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; 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, packet_info *pinfo, proto_tree *tree, guint offset) { 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 fVtDataAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* BOOLEAN */ offset = fBooleanTag(tvb, pinfo, tree, offset, "all New Data Accepted: "); break; case 1: /* Unsigned OPTIONAL */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "accepted Octet Count: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fConfirmedAuditNotificationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint firstloop = 1; guint8 tag_no, tag_info; guint32 lvt; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; } if (tag_is_opening(tag_info) && firstloop) { firstloop = 0; offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } offset = fAuditNotificationInfo(tvb, pinfo, tree, offset); if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fUnconfirmedAuditNotificationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fConfirmedAuditNotificationRequest(tvb, pinfo, tree, offset); } static guint fAuditLogQueryByTargetParameters(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* target-device-identifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); break; case 1: /* target-device-address */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fAddress(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* target-object-identifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 3: /* target-property-identifier */ offset = fPropertyIdentifier(tvb, pinfo, tree, offset); break; case 4: /* target-property-array-index */ offset = fPropertyArrayIndex(tvb, pinfo, tree, offset); break; case 5: /* target-priority */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "target-priority: "); break; case 6: /* target-operation */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "target-operation: ", BACnetAuditOperation); break; case 7: /* successful-action */ offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, "target-successful-action: ", BACnetSuccessFilter, 64); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuditLogQueryBySourceParameters(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* source-device-identifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); break; case 1: /* source-device-address */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fAddress(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* source-object-identifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 3: /* source-operation */ offset = fBitStringTagVS(tvb, pinfo, tree, offset, "source-operation: ", BACnetAuditOperation); break; case 4: /* successful-action */ offset = fEnumeratedTagSplit(tvb, pinfo, tree, offset, "source-successful-action: ", BACnetSuccessFilter, 64); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuditLogQueryParameters(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; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* query-by-target-parameters */ subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "target-parameters: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAuditLogQueryByTargetParameters(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 1: /* query-by-source-parameters */ subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "source-parameters: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAuditLogQueryBySourceParameters(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuditLogQueryRequest(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; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* audit-log */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 1: /* query-parameters */ subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "query-parameters: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAuditLogQueryParameters(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* start-at-sequence-number */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "start-at-sequence-number: "); break; case 3: /* requested-count */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "requested-count: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuditLogRecordResult(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; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0 : /* sequence-number */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "sequence-number: "); break; case 1: /* log-record */ subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "log-record: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAuditLogRecord(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuditLogQueryAck(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; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* audit-log */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 1: /* records */ subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "records: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAuditLogRecordResult(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* no-more-items */ offset = fBooleanTag(tvb, pinfo, tree, offset, "no-more-items: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fWhoAmIRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; offset = fApplicationTypes(tvb, pinfo, tree, offset, "Vendor ID: "); offset = fApplicationTypes(tvb, pinfo, tree, offset, "Model name: "); offset = fApplicationTypes(tvb, pinfo, tree, offset, "Serial number: "); if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fYouAreRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; offset = fApplicationTypes(tvb, pinfo, tree, offset, "Vendor ID: "); offset = fApplicationTypes(tvb, pinfo, tree, offset, "Model name: "); offset = fApplicationTypes(tvb, pinfo, tree, offset, "Serial number: "); if(tvb_reported_length_remaining(tvb, offset) > 0) { offset = fApplicationTypes(tvb, pinfo, tree, offset, "Device Identifier: "); } if(tvb_reported_length_remaining(tvb, offset) > 0) { offset = fApplicationTypes(tvb, pinfo, tree, offset, "Device MAC address: "); } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuthenticateRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* Unsigned32 */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "pseudo Random Number: "); break; case 1: /* expected Invoke ID Unsigned8 OPTIONAL */ proto_tree_add_item(tree, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN); break; case 2: /* Chararacter String OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "operator Name: "); break; case 3: /* Chararacter String OPTIONAL */ offset = fCharacterString(tvb, pinfo, tree, offset, "operator Password: "); break; case 4: /* Boolean OPTIONAL */ offset = fBooleanTag(tvb, pinfo, tree, offset, "start Encyphered Session: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuthenticateAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fApplicationTypes(tvb, pinfo, tree, offset, "modified Random Number: "); } static guint fAuthenticationFactor(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* format-type */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "format-type: ", NULL); break; case 1: /* format-class */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "format-class: "); break; case 2: /* value */ offset = fOctetString(tvb, pinfo, tree, offset, "value: ", lvt); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuthenticationFactorFormat(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* format-type */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "format-type: ", NULL); break; case 1: /* vendor-id */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "vendor-id: "); break; case 2: /* vendor-format */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "vendor-format: "); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAuthenticationPolicy(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* policy */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; } switch (tag_no) { case 0: /* credential-data-input */ offset = fDeviceObjectReference(tvb, pinfo, tree, offset); break; case 1: /* index */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "index: "); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } break; case 1: /* order-enforced */ offset = fBooleanTag(tvb, pinfo, tree, offset, "order-enforced: "); break; case 2: /* timeout */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "timeout: "); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fRequestKeyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); /* Requesting Device Identifier */ offset = fAddress(tvb, pinfo, tree, offset); offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); /* Remote Device Identifier */ return fAddress(tvb, pinfo, tree, offset); } static guint fRemoveListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* Same as AddListElement request after service choice */ return fAddListElementRequest(tvb, pinfo, tree, offset); } static guint fReadPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fBACnetObjectPropertyReference(tvb, pinfo, tree, offset); } static guint fReadPropertyAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; /* set the optional global properties to indicate not-used */ propertyArrayIndex = -1; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { offset += len; subtree = tree; continue; } switch (tag_no) { case 0: /* objectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 1: /* propertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, subtree, offset); break; case 2: /* propertyArrayIndex */ offset = fPropertyArrayIndex(tvb, pinfo, subtree, offset); break; case 3: /* propertyValue */ 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, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; /* set the optional global properties to indicate not-used */ propertyArrayIndex = -1; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* objectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 1: /* propertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, subtree, offset); break; case 2: /* propertyArrayIndex */ offset = fPropertyArrayIndex(tvb, pinfo, subtree, offset); break; case 3: /* propertyValue */ offset = fPropertyValue(tvb, pinfo, subtree, offset, tag_info); break; case 4: /* Priority (only used for write) */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "Priority: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fWriteAccessSpecification(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0, len; guint8 tag_no, tag_info; guint32 lvt; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, 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, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 1: /* listOfPropertyValues */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyValue(tvb, pinfo, subtree, offset); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fWritePropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { if (offset >= tvb_reported_length(tvb)) return offset; col_set_writable(pinfo->cinfo, COL_INFO, FALSE); /* don't set all infos into INFO column */ return fWriteAccessSpecification(tvb, pinfo, tree, offset); } static guint 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; /* set the optional global properties to indicate not-used */ propertyArrayIndex = -1; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, 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, pinfo, tree, offset); break; case 1: /* propertyArrayIndex */ offset = fPropertyArrayIndex(tvb, pinfo, tree, offset); if (list != 0) break; /* Continue decoding if this may be a list */ /* FALLTHROUGH */ default: lastoffset = offset; /* Set loop end condition */ break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fBACnetPropertyReference(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 list) { col_set_writable(pinfo->cinfo, COL_INFO, FALSE); /* don't set all infos into INFO column */ return fPropertyReference(tvb, pinfo, tree, offset, 0, list); } static guint fBACnetObjectPropertyReference(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* ObjectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 1: /* PropertyIdentifier and propertyArrayIndex */ offset = fPropertyReference(tvb, pinfo, tree, offset, 1, 0); col_set_writable(pinfo->cinfo, COL_INFO, FALSE); /* don't set all infos into INFO column */ /* FALLTHROUGH */ default: lastoffset = offset; /* Set loop end condition */ break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } #if 0 static guint fObjectPropertyValue(tvbuff_t *tvb, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree* subtree = tree; proto_item* tt; while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); continue; } switch (tag_no) { case 0: /* ObjectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 1: /* PropertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, subtree, offset); break; case 2: /* propertyArrayIndex */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "property Array Index: "); break; case 3: /* Value */ offset = fPropertyValue(tvb, pinfo, subtree, offset, tag_info); break; case 4: /* Priority */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "Priority: "); break; default: break; } } return offset; } #endif static guint fPriorityArray(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { char i = 1, ar[256]; guint lastoffset = 0; guint8 tag_no; guint8 tag_info; guint32 lvt; 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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; snprintf(ar, sizeof(ar), "%s[%d]: ", val_to_split_str(87 , 512, BACnetPropertyIdentifier, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), i++); fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if ( ! tag_is_context_specific(tag_info)) { /* DMR Should be fAbstractNSyntax, but that's where we came from! */ offset = fApplicationTypes(tvb, pinfo, tree, offset, ar); } else { if (tag_is_opening(tag_info) && tag_no == 0) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else if (tag_is_opening(tag_info) && tag_no == 1) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fDate(tvb, pinfo, tree, offset, "Date: "); offset = fTime(tvb, pinfo, tree, offset, "Time: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else if (tag_is_opening(tag_info) && tag_no == 2) { offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fXyColor(tvb, pinfo, tree, offset, "xy-color: "); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); } else { /* 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; } static guint fDeviceObjectReference(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot an un-matched closing tag */ if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* deviceIdentifier - OPTIONAL */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "DeviceIdentifier: "); break; case 1: /* ObjectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fSpecialEvent(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot an un-matched closing tag */ if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* calendarEntry */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fCalendarEntry(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } break; case 1: /* calendarReference */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 2: /* list of BACnetTimeValue */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fTimeValue(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; case 3: /* eventPriority */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "event priority: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fNetworkSecurityPolicy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree; subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_tag, NULL, "network security policy"); while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* port-id */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "port-id: "); break; case 1: /* security-level */ offset = fEnumeratedTag(tvb, pinfo, subtree, offset, "security-level: ", BACnetSecurityPolicy); break; default: return offset; } } return offset; } static guint fKeyIdentifier(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) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* algorithm */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "algorithm: "); break; case 1: /* key-id */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "key-id: "); break; default: return offset; } } return offset; } static guint fSecurityKeySet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree; subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_tag, NULL, "security keyset"); while (tvb_reported_length_remaining(tvb, offset) > 0 && offset > lastoffset) { lastoffset = offset; /* check the tag. A closing tag means we are done */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { return offset; } switch (tag_no) { case 0: /* key-revision */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "key-revision: "); break; case 1: /* activation-time */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, subtree, offset, "activation-time: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 2: /* expiration-time */ offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fDateTime(tvb, pinfo, subtree, offset, "expiration-time: "); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); break; case 3: /* key-ids */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fKeyIdentifier(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: return offset; } } return offset; } static guint fSelectionCriteria(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { break; } switch (fTagNo(tvb, offset)) { case 0: /* propertyIdentifier */ offset = fPropertyIdentifier(tvb, pinfo, tree, offset); break; case 1: /* propertyArrayIndex */ offset = fPropertyArrayIndex(tvb, pinfo, tree, offset); break; case 2: /* relationSpecifier */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "relation Specifier: ", BACnetRelationSpecifier); break; case 3: /* comparisonValue */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, 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, packet_info *pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* selectionLogic */ offset = fEnumeratedTag(tvb, pinfo, subtree, offset, "selection Logic: ", BACnetSelectionLogic); break; case 1: /* listOfSelectionCriteria */ if (tag_is_opening(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fSelectionCriteria(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fReadPropertyConditionalRequest(tvbuff_t *tvb, packet_info* pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader (tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info) && tag_no < 2) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); 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; } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fReadAccessSpecification(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; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* objectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; case 1: /* listOfPropertyReferences */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "listOfPropertyReferences"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetPropertyReference(tvb, pinfo, subtree, offset, 1); } else if (tag_is_closing(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, 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 fReadAccessResult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0, len; guint8 tag_no; guint8 tag_info; guint32 lvt; proto_tree *subtree = tree; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; len = fTagHeader(tvb, pinfo, 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 */ if (tag_no == 1) { /* closing list of results for this objectSpecifier */ fTagHeaderTree(tvb, pinfo, subtree, offset - len, &tag_no, &tag_info, &lvt); /* look if another objectSpecifier follows here */ if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; /* nothing more to decode left */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_no != 0 || tag_info != 12) return offset; /* no objectSpecifier */ } continue; } switch (tag_no) { case 0: /* objectSpecifier */ offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); break; case 1: /* list of Results */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, "listOfResults"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; case 2: /* propertyIdentifier */ offset = fPropertyIdentifierValue(tvb, pinfo, subtree, offset, 2); break; case 5: /* propertyAccessError */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "propertyAccessError"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); /* Error Code follows */ offset = fError(tvb, pinfo, subtree, offset); fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fReadPropertyConditionalAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* listOfReadAccessResults */ return fReadAccessResult(tvb, pinfo, tree, offset); } static guint fCreateObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { guint lastoffset = 0; guint8 tag_no, tag_info; guint32 lvt; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_no < 2) { offset += fTagHeaderTree(tvb, pinfo, 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, pinfo, subtree, offset, "Object Type: ", BACnetObjectType, 128); break; case 1: /* objectIdentifier */ offset = fObjectIdentifier(tvb, pinfo, subtree, offset, "ObjectIdentifier: "); break; default: break; } break; case 1: /* propertyValue */ if (tag_is_opening(tag_info)) { offset = fBACnetPropertyValue(tvb, pinfo, subtree, offset); } else { expert_add_info(pinfo, subtree, &ei_bacapp_bad_tag); } break; default: break; } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fCreateObjectAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { return fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); } static guint fReadRangeRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; offset = fBACnetObjectPropertyReference(tvb, pinfo, subtree, offset); if (tvb_reported_length_remaining(tvb, offset) > 0) { /* optional range choice */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, val_to_str_const(tag_no, BACnetReadRangeOptions, "unknown range option")); offset += fTagHeaderTree(tvb, pinfo, 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; case 4: /* range byTime - deprecated in 2004 */ case 7: /* 2004 spec */ offset = fDateTime(tvb, pinfo, subtree, offset, "reference Date/Time: "); offset = fApplicationTypes(tvb, pinfo, subtree, offset, "reference Count: "); break; case 5: /* range timeRange - deprecated in 2004 */ offset = fDateTime(tvb, pinfo, subtree, offset, "beginning Time: "); offset = fDateTime(tvb, pinfo, subtree, offset, "ending Time: "); break; default: break; } offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } } return offset; } static guint fReadRangeAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; /* 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, pinfo, tree, offset, "resultFlags: ", BACnetResultFlags); /* itemCount */ offset = fUnsignedTag(tvb, pinfo, subtree, offset, "item Count: "); /* itemData */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info)) { col_set_writable(pinfo->cinfo, COL_INFO, FALSE); /* don't set all infos into INFO column */ subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "itemData"); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } /* firstSequenceNumber - OPTIONAL */ if (tvb_reported_length_remaining(tvb, offset) > 0) { offset = fUnsignedTag(tvb, pinfo, subtree, offset, "first Sequence Number: "); } return 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_tree* subtree = NULL; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(tree, tvb, offset, 1, ett_bacapp_value, NULL, val_to_str_const(tag_no, BACnetFileAccessOption, "invalid access method")); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fApplicationTypes(tvb, pinfo, subtree, offset, val_to_str_const(tag_no, BACnetFileStartOption, "invalid option")); offset = fApplicationTypes(tvb, pinfo, subtree, offset, val_to_str_const(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: "); } } if ((bacapp_flags & BACAPP_MORE_SEGMENTS) == 0) { /* More Flag is not set, so we can look for closing tag in this segment */ fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_closing(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } } } return offset; } static guint fAccessRule(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) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); /* quit loop if we spot a closing tag */ if (tag_is_closing(tag_info)) { break; } switch (tag_no) { case 0: /* time-range-specifier */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "time-range-specifier: ", NULL); break; case 1: /* time-range */ offset = fDeviceObjectPropertyReference(tvb, pinfo, tree, offset); break; case 2: /* location-specifier */ offset = fEnumeratedTag(tvb, pinfo, tree, offset, "location-specifier: ", NULL); break; case 3: /* location */ offset = fDeviceObjectReference(tvb, pinfo, tree, offset); break; case 4: /* enable */ offset = fBooleanTag(tvb, pinfo, tree, offset, "enable: "); break; default: break; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fAtomicReadFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no, tag_info; guint32 lvt; proto_tree *subtree = tree; offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, val_to_str_const(tag_no, BACnetFileAccessOption, "unknown access method")); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fSignedTag(tvb, pinfo, subtree, offset, val_to_str_const(tag_no, BACnetFileStartOption, "unknown option")); offset = fUnsignedTag(tvb, pinfo, subtree, offset, val_to_str_const(tag_no, BACnetFileRequestCount, "unknown option")); offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); } return offset; } static guint fAtomicWriteFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { offset = fObjectIdentifier(tvb, pinfo, tree, offset, "ObjectIdentifier: "); /* file Identifier */ offset = fAccessMethod(tvb, pinfo, tree, offset); return offset; } static guint fAtomicWriteFileAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint tag_no = fTagNo(tvb, offset); return fSignedTag(tvb, pinfo, tree, offset, val_to_str_const(tag_no, BACnetFileStartOption, "unknown option")); } static guint fAtomicReadFileAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { offset = fApplicationTypes(tvb, pinfo, tree, offset, "End Of File: "); offset = fAccessMethod(tvb, pinfo, tree, offset); return offset; } static guint fReadPropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset) { col_set_writable(pinfo->cinfo, COL_INFO, FALSE); /* don't set all infos into INFO column */ return fReadAccessSpecification(tvb, pinfo, subtree, offset); } static guint fReadPropertyMultipleAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { col_set_writable(pinfo->cinfo, COL_INFO, FALSE); /* don't set all infos into INFO column */ return fReadAccessResult(tvb, pinfo, tree, offset); } static guint fConfirmedServiceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice) { if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; switch (service_choice) { case 0: /* acknowledgeAlarm */ offset = fAcknowledgeAlarmRequest(tvb, pinfo, tree, offset); break; case 1: /* confirmedCOVNotification */ offset = fConfirmedCOVNotificationRequest(tvb, pinfo, tree, offset); break; case 2: /* confirmedEventNotification */ offset = fConfirmedEventNotificationRequest(tvb, pinfo, tree, offset); break; case 3: /* confirmedGetAlarmSummary conveys no parameters */ break; case 4: /* getEnrollmentSummaryRequest */ offset = fGetEnrollmentSummaryRequest(tvb, pinfo, tree, offset); break; case 5: /* subscribeCOVRequest */ offset = fSubscribeCOVRequest(tvb, pinfo, tree, offset); break; case 6: /* atomicReadFile-Request */ offset = fAtomicReadFileRequest(tvb, pinfo, tree, offset); break; case 7: /* atomicWriteFile-Request */ offset = fAtomicWriteFileRequest(tvb, pinfo, tree, offset); break; case 8: /* AddListElement-Request */ offset = fAddListElementRequest(tvb, pinfo, tree, offset); break; case 9: /* removeListElement-Request */ offset = fRemoveListElementRequest(tvb, pinfo, tree, offset); break; case 10: /* createObjectRequest */ offset = fCreateObjectRequest(tvb, pinfo, tree, offset); break; case 11: /* deleteObject */ offset = fDeleteObjectRequest(tvb, pinfo, tree, offset); break; case 12: offset = fReadPropertyRequest(tvb, pinfo, tree, offset); break; case 13: offset = fReadPropertyConditionalRequest(tvb, pinfo, tree, offset); break; case 14: offset = fReadPropertyMultipleRequest(tvb, pinfo, tree, offset); break; case 15: offset = fWritePropertyRequest(tvb, pinfo, tree, offset); break; case 16: offset = fWritePropertyMultipleRequest(tvb, pinfo, tree, offset); break; case 17: offset = fDeviceCommunicationControlRequest(tvb, pinfo, tree, offset); break; case 18: offset = fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset); break; case 19: offset = fConfirmedTextMessageRequest(tvb, pinfo, tree, offset); break; case 20: offset = fReinitializeDeviceRequest(tvb, pinfo, tree, offset); break; case 21: offset = fVtOpenRequest(tvb, pinfo, tree, offset); break; case 22: offset = fVtCloseRequest(tvb, pinfo, tree, offset); break; case 23: offset = fVtDataRequest(tvb, pinfo, tree, offset); break; case 24: offset = fAuthenticateRequest(tvb, pinfo, tree, offset); break; case 25: offset = fRequestKeyRequest(tvb, pinfo, tree, offset); break; case 26: offset = fReadRangeRequest(tvb, pinfo, tree, offset); break; case 27: offset = fLifeSafetyOperationRequest(tvb, pinfo, tree, offset, NULL); break; case 28: offset = fSubscribeCOVPropertyRequest(tvb, pinfo, tree, offset); break; case 29: offset = fGetEventInformationRequest(tvb, pinfo, tree, offset); break; case 30: offset = fSubscribeCOVPropertyMultipleRequest(tvb, pinfo, tree, offset); break; case 31: offset = fConfirmedCOVNotificationMultipleRequest(tvb, pinfo, tree, offset); break; case 32: offset = fConfirmedAuditNotificationRequest(tvb, pinfo, tree, offset); break; case 33: offset = fAuditLogQueryRequest(tvb, pinfo, tree, offset); break; default: return offset; } return offset; } static guint fConfirmedServiceAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice) { if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; switch (service_choice) { case 3: /* confirmedEventNotificationAck */ offset = fGetAlarmSummaryAck(tvb, pinfo, tree, offset); break; case 4: /* getEnrollmentSummaryAck */ offset = fGetEnrollmentSummaryAck(tvb, pinfo, tree, offset); break; case 6: /* atomicReadFile */ offset = fAtomicReadFileAck(tvb, pinfo, tree, offset); break; case 7: /* atomicReadFileAck */ offset = fAtomicWriteFileAck(tvb, pinfo, tree, offset); break; case 10: /* createObject */ offset = fCreateObjectAck(tvb, pinfo, tree, offset); break; case 12: offset = fReadPropertyAck(tvb, pinfo, tree, offset); break; case 13: offset = fReadPropertyConditionalAck(tvb, pinfo, tree, offset); break; case 14: offset = fReadPropertyMultipleAck(tvb, pinfo, tree, offset); break; case 18: offset = fConfirmedPrivateTransferAck(tvb, pinfo, tree, offset); break; case 21: offset = fVtOpenAck(tvb, pinfo, tree, offset); break; case 23: offset = fVtDataAck(tvb, pinfo, tree, offset); break; case 24: offset = fAuthenticateAck(tvb, pinfo, tree, offset); break; case 26: offset = fReadRangeAck(tvb, pinfo, tree, offset); break; case 29: offset = fGetEventInformationACK(tvb, pinfo, tree, offset); break; case 33: offset = fAuditLogQueryAck(tvb, pinfo, tree, offset); break; default: return offset; } return offset; } static guint fIAmRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* BACnetObjectIdentifier */ offset = fApplicationTypes(tvb, pinfo, tree, offset, "BACnet Object Identifier: "); /* MaxAPDULengthAccepted */ offset = fApplicationTypes(tvb, pinfo, tree, offset, "Maximum ADPU Length Accepted: "); /* segmentationSupported */ offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, "Segmentation Supported: ", BACnetSegmentation); /* vendor ID */ return fVendorIdentifier(tvb, pinfo, tree, offset); } static guint fIHaveRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* BACnetDeviceIdentifier */ offset = fApplicationTypes(tvb, pinfo, tree, offset, "Device Identifier: "); /* BACnetObjectIdentifier */ offset = fApplicationTypes(tvb, pinfo, tree, offset, "Object Identifier: "); /* ObjectName */ return fObjectName(tvb, pinfo, tree, offset); } static guint fWhoIsRequest(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint val; guint8 tag_len; guint8 tag_no, tag_info; guint32 lvt; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* DeviceInstanceRangeLowLimit Optional */ if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) col_append_fstr(pinfo->cinfo, COL_INFO, "%d ", val); offset = fDevice_Instance(tvb, pinfo, tree, offset, hf_Device_Instance_Range_Low_Limit); break; case 1: /* DeviceInstanceRangeHighLimit Optional but required if DeviceInstanceRangeLowLimit is there */ if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) col_append_fstr(pinfo->cinfo, COL_INFO, "%d ", val); offset = fDevice_Instance(tvb, pinfo, tree, offset, hf_Device_Instance_Range_High_Limit); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fUnconfirmedServiceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice) { if (tvb_reported_length_remaining(tvb, offset) <= 0) return offset; switch (service_choice) { case 0: /* I-Am-Request */ offset = fIAmRequest(tvb, pinfo, tree, offset); break; case 1: /* i-Have Request */ offset = fIHaveRequest(tvb, pinfo, tree, offset); break; case 2: /* unconfirmedCOVNotification */ offset = fUnconfirmedCOVNotificationRequest(tvb, pinfo, tree, offset); break; case 3: /* unconfirmedEventNotification */ offset = fUnconfirmedEventNotificationRequest(tvb, pinfo, tree, offset); break; case 4: /* unconfirmedPrivateTransfer */ offset = fUnconfirmedPrivateTransferRequest(tvb, pinfo, tree, offset); break; case 5: /* unconfirmedTextMessage */ offset = fUnconfirmedTextMessageRequest(tvb, pinfo, tree, offset); break; case 6: /* timeSynchronization */ offset = fTimeSynchronizationRequest(tvb, pinfo, tree, offset); break; case 7: /* who-Has */ offset = fWhoHas(tvb, pinfo, tree, offset); break; case 8: /* who-Is */ offset = fWhoIsRequest(tvb, pinfo, tree, offset); break; case 9: /* utcTimeSynchronization */ offset = fUTCTimeSynchronizationRequest(tvb, pinfo, tree, offset); break; case 10: offset = fWriteGroupRequest(tvb, pinfo, tree, offset); break; case 11: offset = fUnconfirmedCOVNotificationMultipleRequest(tvb, pinfo, tree, offset); break; case 12: offset = fUnconfirmedAuditNotificationRequest(tvb, pinfo, tree, offset); break; case 13: offset = fWhoAmIRequest(tvb, pinfo, tree, offset); break; case 14: offset = fYouAreRequest(tvb, pinfo, tree, offset); break; default: break; } return offset; } static guint fStartConfirmed(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset, guint8 ack, gint *svc, proto_item **tt) { proto_item *tc; proto_tree *bacapp_tree_control; gint tmp; guint extra = 2; bacapp_seq = 0; tmp = tvb_get_gint8(tvb, offset); bacapp_flags = tmp & 0x0f; if (ack == 0) { extra = 3; } *svc = tvb_get_gint8(tvb, offset+extra); if (bacapp_flags & 0x08) *svc = tvb_get_gint8(tvb, offset+extra+2); proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, ENC_BIG_ENDIAN); tc = proto_tree_add_item(bacapp_tree, hf_bacapp_pduflags, tvb, offset, 1, ENC_BIG_ENDIAN); bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp_control); proto_tree_add_item(bacapp_tree_control, hf_bacapp_SEG, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, offset, 1, ENC_BIG_ENDIAN); if (ack == 0) { /* The following are for ConfirmedRequest, not Complex ack */ proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree, hf_bacapp_response_segments, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree, hf_bacapp_max_adpu_size, tvb, offset, 1, ENC_BIG_ENDIAN); } offset++; proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN); if (bacapp_flags & 0x08) { bacapp_seq = tvb_get_guint8(tvb, offset); proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb, offset++, 1, ENC_BIG_ENDIAN); } *tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb, offset++, 1, ENC_BIG_ENDIAN); return offset; } static guint 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, pinfo, bacapp_tree, offset, 0, &svc, &tt); return fContinueConfirmedRequestPDU(tvb, pinfo, bacapp_tree, offset, svc); } static guint 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, ENC_BIG_ENDIAN); tmp = tvb_get_guint8(tvb, offset); proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb, offset++, 1, ENC_BIG_ENDIAN); /* Service Request follows... Variable Encoding 20.2ff */ return fUnconfirmedServiceRequest(tvb, pinfo, bacapp_tree, offset, tmp); } static guint fSimpleAckPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset) { /* BACnet-Simple-Ack-PDU */ /* ASHRAE 135-2001 20.1.4 */ proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb, offset++, 1, ENC_BIG_ENDIAN); return offset; } static guint 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, pinfo, bacapp_tree, offset, 1, &svc, &tt); return fContinueComplexAckPDU(tvb, pinfo, bacapp_tree, offset, svc); } static guint 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, ENC_BIG_ENDIAN); bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); proto_tree_add_item(bacapp_tree_control, hf_bacapp_NAK, tvb, offset, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree_control, hf_bacapp_SRV, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree_control, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree_control, hf_bacapp_sequence_number, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree_control, hf_bacapp_window_size, tvb, offset++, 1, ENC_BIG_ENDIAN); return 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, pinfo, tree, offset, &parsed_tag, &tag_info, &lvt); offset = fError(tvb, pinfo, tree, offset); return offset + fTagHeaderTree(tvb, pinfo, tree, offset, &parsed_tag, &tag_info, &lvt); } static guint 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; guint vendor_identifier = 0; guint service_number = 0; guint8 tag_len = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); switch (tag_no) { case 0: /* errorType */ offset = fContextTaggedError(tvb, pinfo, subtree, offset); break; case 1: /* vendorID */ fUnsigned32(tvb, offset+tag_len, lvt, &vendor_identifier); col_append_fstr(pinfo->cinfo, COL_INFO, "V=%u ", vendor_identifier); offset = fVendorIdentifier(tvb, pinfo, subtree, offset); break; case 2: /* serviceNumber */ fUnsigned32(tvb, offset+tag_len, lvt, &service_number); col_append_fstr(pinfo->cinfo, COL_INFO, "SN=%u ", service_number); offset = fUnsignedTag(tvb, pinfo, subtree, offset, "service Number: "); break; case 3: /* errorParameters */ if (tag_is_opening(tag_info)) { subtree = proto_tree_add_subtree(subtree, tvb, offset, 1, ett_bacapp_value, NULL, "error Parameters"); propertyIdentifier = -1; offset += fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset); } else if (tag_is_closing(tag_info)) { offset += fTagHeaderTree(tvb, pinfo, 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 fCreateObjectError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* errorType */ offset = fContextTaggedError(tvb, pinfo, tree, offset); break; case 1: /* firstFailedElementNumber */ offset = fUnsignedTag(tvb, pinfo, tree, offset, "first failed element number: "); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fChangeListError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { /* Identical to CreateObjectError */ return fCreateObjectError(tvb, pinfo, tree, offset); } static guint fVTCloseError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint8 tag_no = 0, tag_info = 0; guint32 lvt = 0; if (fTagNo(tvb, offset) == 0) { /* errorType */ offset = fContextTaggedError(tvb, pinfo, tree, offset); if (fTagNo(tvb, offset) == 1) { /* listOfVTSessionIdentifiers [OPTIONAL] */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fVtCloseRequest(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, 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, packet_info *pinfo, proto_tree *tree, guint offset) { guint lastoffset = 0; guint8 tag_no = 0, tag_info = 0; guint32 lvt = 0; col_set_writable(pinfo->cinfo, COL_INFO, FALSE); /* don't set all infos into INFO column */ while (tvb_reported_length_remaining(tvb, offset) > 0) { /* exit loop if nothing happens inside */ lastoffset = offset; switch (fTagNo(tvb, offset)) { case 0: /* errorType */ offset = fContextTaggedError(tvb, pinfo, tree, offset); break; case 1: /* firstFailedWriteAttempt */ offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); offset = fBACnetObjectPropertyReference(tvb, pinfo, tree, offset); offset += fTagHeaderTree(tvb, pinfo, tree, offset, &tag_no, &tag_info, &lvt); break; default: return offset; } if (offset <= lastoffset) break; /* nothing happened, exit loop */ } return offset; } static guint fErrorClass(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 val = 0, lvt; guint8 tag_no, tag_info; proto_item *ti; proto_tree *subtree; guint tag_len; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) { ti = proto_tree_add_uint(tree, hf_bacapp_error_class, tvb, offset, lvt+tag_len, val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "Error Class - %u octets (Signed)", lvt); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += tag_len + lvt; return offset; } static guint fErrorCode(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { guint32 val = 0, lvt; guint8 tag_no, tag_info; proto_item *ti; proto_tree *subtree; guint tag_len; tag_len = fTagHeader(tvb, pinfo, offset, &tag_no, &tag_info, &lvt); if (fUnsigned32(tvb, offset+tag_len, lvt, &val)) { ti = proto_tree_add_uint(tree, hf_bacapp_error_code, tvb, offset, lvt+tag_len, val); subtree = proto_item_add_subtree(ti, ett_bacapp_tag); } else { subtree = proto_tree_add_subtree_format(tree, tvb, offset, lvt+tag_len, ett_bacapp_tag, NULL, "Error Code - %u octets (Signed)", lvt); } fTagHeaderTree(tvb, pinfo, subtree, offset, &tag_no, &tag_info, &lvt); offset += tag_len + lvt; return offset; } static guint fError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset) { offset = fErrorClass(tvb, pinfo, tree, offset); return fErrorCode(tvb, pinfo, tree, offset); } static guint fBACnetError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint service) { switch (service) { case 8: offset = fChangeListError(tvb, pinfo, tree, offset); break; 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; case 30: offset = fSubscribeCOVPropertyMultipleError(tvb, pinfo, tree, offset); break; default: offset = fError(tvb, pinfo, tree, offset); break; } return offset; } static guint 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; proto_tree *bacapp_tree_control; guint8 tmp; tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, ENC_BIG_ENDIAN); bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); proto_tree_add_item(bacapp_tree_control, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN); tmp = tvb_get_guint8(tvb, offset); proto_tree_add_item(bacapp_tree_control, hf_bacapp_service, tvb, offset++, 1, ENC_BIG_ENDIAN); /* Error Handling follows... */ return fBACnetError(tvb, pinfo, bacapp_tree, offset, tmp); } static guint 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, ENC_BIG_ENDIAN); bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); proto_tree_add_item(bacapp_tree_control, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree_control, hf_BACnetRejectReason, tvb, offset++, 1, ENC_BIG_ENDIAN); return offset; } static guint 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, ENC_BIG_ENDIAN); bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); proto_tree_add_item(bacapp_tree_control, hf_bacapp_SRV, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree_control, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN); proto_tree_add_item(bacapp_tree_control, hf_BACnetAbortReason, tvb, offset++, 1, ENC_BIG_ENDIAN); return offset; } static guint do_the_dissection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { guint8 flag, bacapp_type; guint offset = 0; flag = tvb_get_gint8(tvb, 0); bacapp_type = (flag >> 4) & 0x0f; if (tvb == 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 int dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) { guint8 flag, bacapp_type; guint save_fragmented = FALSE, data_offset = 0, /*bacapp_apdu_size,*/ fragment = FALSE; tvbuff_t *new_tvb = NULL; guint offset = 0; 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 = NULL; gint svc = 0; proto_item *tt = 0; gint8 ack = 0; /* Strings for BACnet Statistics */ const gchar errstr[] = "ERROR: "; const gchar rejstr[] = "REJECTED: "; const gchar abortstr[] = "ABORTED: "; const gchar sackstr[] = " (SimpleAck)"; const gchar cackstr[] = " (ComplexAck)"; const gchar uconfsreqstr[] = " (Unconfirmed Service Request)"; const gchar confsreqstr[] = " (Confirmed Service Request)"; col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU"); col_clear(pinfo->cinfo, COL_INFO); flag = tvb_get_guint8(tvb, 0); bacapp_type = (flag >> 4) & 0x0f; /* show some descriptive text in the INFO column */ col_add_fstr(pinfo->cinfo, COL_INFO, "%-16s", val_to_str_const(bacapp_type, BACnetTypeName, "# unknown APDU #")); bacinfo.service_type = NULL; bacinfo.invoke_id = NULL; bacinfo.instance_ident = NULL; bacinfo.object_ident = NULL; switch (bacapp_type) { case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: /* segmented messages have 2 additional bytes */ if (flag & BACAPP_SEGMENTED_REQUEST) { 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_const(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), bacapp_invoke_id); updateBacnetInfoValue(BACINFO_INVOKEID, wmem_strdup_printf(pinfo->pool, "Invoke ID: %d", bacapp_invoke_id)); updateBacnetInfoValue(BACINFO_SERVICE, wmem_strconcat(pinfo->pool, val_to_str_const(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), confsreqstr, NULL)); 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_const(bacapp_service, BACnetUnconfirmedServiceChoice, bacapp_unknown_service_str)); updateBacnetInfoValue(BACINFO_SERVICE, wmem_strconcat(pinfo->pool, val_to_str_const(bacapp_service, BACnetUnconfirmedServiceChoice, bacapp_unknown_service_str), uconfsreqstr, NULL)); 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_const(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), bacapp_invoke_id); updateBacnetInfoValue(BACINFO_INVOKEID, wmem_strdup_printf(pinfo->pool, "Invoke ID: %d", bacapp_invoke_id)); updateBacnetInfoValue(BACINFO_SERVICE, wmem_strconcat(pinfo->pool, val_to_str_const(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), sackstr, NULL)); break; case BACAPP_TYPE_COMPLEX_ACK: /* segmented messages have 2 additional bytes */ if (flag & BACAPP_SEGMENTED_REQUEST) { fragment = TRUE; ack = 1; /* bacapp_apdu_size = fGetMaxAPDUSize(0); */ /* has minimum of 50 Bytes */ bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); 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, "%s[%3u] ", /* "original-invokeID" replaced */ val_to_str_const(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), bacapp_invoke_id); updateBacnetInfoValue(BACINFO_INVOKEID, wmem_strdup_printf(pinfo->pool, "Invoke ID: %d", bacapp_invoke_id)); updateBacnetInfoValue(BACINFO_SERVICE, wmem_strconcat(pinfo->pool, val_to_str_const(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), cackstr, NULL)); 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_const(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), bacapp_invoke_id); updateBacnetInfoValue(BACINFO_INVOKEID, wmem_strdup_printf(pinfo->pool, "Invoke ID: %d", bacapp_invoke_id)); updateBacnetInfoValue(BACINFO_SERVICE, wmem_strconcat(pinfo->pool, errstr, val_to_str_const(bacapp_service, BACnetConfirmedServiceChoice, bacapp_unknown_service_str), NULL)); 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); updateBacnetInfoValue(BACINFO_INVOKEID, wmem_strdup_printf(pinfo->pool, "Invoke ID: %d", bacapp_invoke_id)); updateBacnetInfoValue(BACINFO_SERVICE, wmem_strconcat(pinfo->pool, rejstr, val_to_split_str(bacapp_reason, 64, BACnetRejectReason, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), NULL)); break; case BACAPP_TYPE_ABORT: bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1); 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); updateBacnetInfoValue(BACINFO_INVOKEID, wmem_strdup_printf(pinfo->pool, "Invoke ID: %d", bacapp_invoke_id)); updateBacnetInfoValue(BACINFO_SERVICE, wmem_strconcat(pinfo->pool, abortstr, val_to_split_str(bacapp_reason, 64, BACnetAbortReason, ASHRAE_Reserved_Fmt, Vendor_Proprietary_Fmt), NULL)); break; /* UNKNOWN */ default: /* nothing more to add */ break; } save_fragmented = pinfo->fragmented; ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, ENC_NA); bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); if (!fragment) 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_head *frag_msg; pinfo->fragmented = TRUE; frag_msg = fragment_add_seq_check(&msg_reassembly_table, tvb, data_offset, pinfo, bacapp_invoke_id, /* ID for fragments belonging together */ NULL, 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_COMPLEX_ACK: fContinueComplexAckPDU(new_tvb, pinfo, bacapp_tree, 0, svc); break; default: /* do nothing */ break; } } } pinfo->fragmented = save_fragmented; /* tapping */ tap_queue_packet(bacapp_tap, pinfo, &bacinfo); return tvb_captured_length(tvb); } void proto_register_bacapp(void) { static hf_register_info hf[] = { { &hf_bacapp_type, { "APDU Type", "bacapp.type", FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, NULL, HFILL } }, { &hf_bacapp_pduflags, { "PDU Flags", "bacapp.pduflags", FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL } }, { &hf_bacapp_SEG, { "Segmented Request", "bacapp.segmented_request", FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, NULL, HFILL } }, { &hf_bacapp_MOR, { "More Segments", "bacapp.more_segments", FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL } }, { &hf_bacapp_SA, { "SA", "bacapp.SA", FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL } }, { &hf_bacapp_max_adpu_size, { "Size of Maximum ADPU accepted", "bacapp.max_adpu_size", FT_UINT8, BASE_DEC, VALS(BACnetMaxAPDULengthAccepted), 0x0f, NULL, HFILL } }, { &hf_bacapp_response_segments, { "Max Response Segments accepted", "bacapp.response_segments", FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0x70, NULL, HFILL } }, { &hf_bacapp_objectType, { "Object Type", "bacapp.objectType", FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, NULL, HFILL } }, { &hf_bacapp_object_name, { "Object Name", "bacapp.object_name", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_instanceNumber, { "Instance Number", "bacapp.instance_number", 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|BASE_EXT_STRING, &BACnetVendorIdentifiers_ext, 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, NULL, HFILL } }, { &hf_bacapp_sequence_number, { "Sequence Number", "bacapp.sequence_number", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_window_size, { "Proposed Window Size", "bacapp.window_size", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_service, { "Service Choice", "bacapp.confirmed_service", 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, NULL, HFILL } }, { &hf_bacapp_NAK, { "NAK", "bacapp.NAK", FT_BOOLEAN, 8, NULL, 0x02, "negative ACK", HFILL } }, { &hf_bacapp_SRV, { "SRV", "bacapp.SRV", FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL } }, { &hf_bacapp_event_type, { "Event Type", "bacapp.event_type", FT_UINT32, BASE_DEC, VALS(BACnetEventType), 0, NULL, HFILL } }, { &hf_bacapp_notify_type, { "Notify Type", "bacapp.notify_type", FT_UINT8, BASE_DEC, VALS(BACnetNotifyType), 0, NULL, HFILL } }, { &hf_bacapp_error_class, { "Error Class", "bacapp.error_class", FT_UINT32, BASE_DEC, VALS(BACnetErrorClass), 0, NULL, HFILL } }, { &hf_bacapp_error_code, { "Error Code", "bacapp.error_code", FT_UINT32, BASE_DEC, VALS(BACnetErrorCode), 0, NULL, HFILL } }, { &hf_bacapp_present_value_null, { "Present Value (null)", "bacapp.present_value.null", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_bool, { "Present Value (bool)", "bacapp.present_value.boolean", FT_BOOLEAN, 8, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_unsigned, { "Present Value (uint)", "bacapp.present_value.uint", FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_signed, { "Present Value (int)", "bacapp.present_value.int", FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_real, { "Present Value (real)", "bacapp.present_value.real", FT_DOUBLE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_double, { "Present Value (double)", "bacapp.present_value.double", FT_DOUBLE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_octet_string, { "Present Value (octet string)", "bacapp.present_value.octet_string", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_char_string, { "Present Value (char string)", "bacapp.present_value.char_string", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_bit_string, { "Present Value (bit string)", "bacapp.present_value.bit_string", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_present_value_enum_index, { "Present Value (enum index)", "bacapp.present_value.enum_index", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_Device_Instance_Range_Low_Limit, { "Device Instance Range Low Limit", "bacapp.who_is.low_limit", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_Device_Instance_Range_High_Limit, { "Device Instance Range High Limit", "bacapp.who_is.high_limit", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_BACnetRejectReason, { "Reject Reason", "bacapp.reject_reason", FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, NULL, HFILL } }, { &hf_BACnetAbortReason, { "Abort Reason", "bacapp.abort_reason", FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 0x00, NULL, HFILL } }, { &hf_BACnetApplicationTagNumber, { "Application Tag Number", "bacapp.application_tag_number", FT_UINT8, BASE_DEC, VALS(BACnetApplicationTagNumber), 0xF0, NULL, HFILL } }, { &hf_BACnetContextTagNumber, { "Context Tag Number", "bacapp.context_tag_number", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL } }, { &hf_BACnetExtendedTagNumber, { "Extended Tag Number", "bacapp.extended_tag_number", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_BACnetNamedTag, { "Named Tag", "bacapp.named_tag", FT_UINT8, BASE_DEC, VALS(BACnetTagNames), 0x07, NULL, HFILL } }, { &hf_BACnetCharacterSet, { "String Character Set", "bacapp.string_character_set", FT_UINT8, BASE_DEC, VALS(BACnetCharacterSet), 0, NULL, HFILL } }, { &hf_BACnetCodePage, { "Code Page", "bacapp.code_page", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_BACnetTagClass, { "Tag Class", "bacapp.tag_class", FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, NULL, HFILL } }, { &hf_bacapp_tag_lvt, { "Length Value Type", "bacapp.LVT", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_tag_ProcessId, { "ProcessIdentifier", "bacapp.processId", FT_UINT32, BASE_DEC, NULL, 0, "Process Identifier", HFILL } }, { &hf_bacapp_tag_to_state, { "To State", "bacapp.to_state", FT_UINT32, BASE_DEC, VALS(BACnetEventState), 0, NULL, HFILL } }, { &hf_bacapp_tag_from_state, { "From State", "bacapp.from_state", FT_UINT32, BASE_DEC, VALS(BACnetEventState), 0, NULL, 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_mac_address_broadcast, { "MAC-address: broadcast", "bacapp.mac_address_broadcast", FT_NONE, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_reserved_ashrea, { "reserved for ASHRAE", "bacapp.reserved_ashrea", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL } }, { &hf_bacapp_unused_bits, { "Unused bits", "bacapp.unused_bits", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_bacapp_bit, { "bit", "bacapp.bit", FT_BOOLEAN, 8, NULL, 0, NULL, HFILL } }, { &hf_bacapp_complete_bitstring, { "Complete bitstring", "bacapp.complete_bitstring", FT_BYTES, BASE_NONE, NULL, 0, NULL, 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_fragment_count, { "Message fragment count", "bacapp.fragment.count", FT_UINT32, BASE_DEC, 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, &ett_bacapp_control, &ett_bacapp_tag, &ett_bacapp_list, &ett_bacapp_value, &ett_msg_fragment, &ett_msg_fragments }; static ei_register_info ei[] = { { &ei_bacapp_bad_length, { "bacapp.bad_length", PI_MALFORMED, PI_ERROR, "Wrong length indicated", EXPFILL }}, { &ei_bacapp_bad_tag, { "bacapp.bad_tag", PI_MALFORMED, PI_ERROR, "Wrong tag found", EXPFILL }}, { &ei_bacapp_opening_tag, { "bacapp.bad_opening_tag", PI_MALFORMED, PI_ERROR, "Expected Opening Tag!", EXPFILL }}, { &ei_bacapp_max_recursion_depth_reached, { "bacapp.max_recursion_depth_reached", PI_PROTOCOL, PI_WARN, "Maximum allowed recursion depth reached. Dissection stopped.", EXPFILL }} }; expert_module_t* expert_bacapp; proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU", "BACapp", "bacapp"); proto_register_field_array(proto_bacapp, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); expert_bacapp = expert_register_protocol(proto_bacapp); expert_register_field_array(expert_bacapp, ei, array_length(ei)); register_dissector("bacapp", dissect_bacapp, proto_bacapp); reassembly_table_register(&msg_reassembly_table, &addresses_reassembly_table_functions); bacapp_dissector_table = register_dissector_table("bacapp.vendor_identifier", "BACapp Vendor Identifier", proto_bacapp, FT_UINT8, BASE_HEX); /* Register BACnet Statistic trees */ register_bacapp_stat_trees(); bacapp_tap = register_tap("bacapp"); /* BACnet statistics tap */ } /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * * Local variables: * c-basic-offset: 4 * tab-width: 8 * indent-tabs-mode: nil * End: * * vi: set shiftwidth=4 tabstop=8 expandtab: * :indentSize=4:tabSize=8:noTabs=true: */