Update BACnet protocol to revision 20.
authorDirk Römmen <dro@cslab.de>
Fri, 12 Oct 2018 14:31:07 +0000 (16:31 +0200)
committerAnders Broman <a.broman58@gmail.com>
Fri, 12 Oct 2018 18:56:22 +0000 (18:56 +0000)
Change-Id: I95370096da31925f3d642d184a1bde3fbbdb265c
Reviewed-on: https://code.wireshark.org/review/30161
Petri-Dish: Anders Broman <a.broman58@gmail.com>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
epan/dissectors/packet-bacapp.c

index f2ae18d8e340ab81f55724db072552fe1efc0929..9444e033ee19031c895e9c02c9aacfce373ba7f9 100644 (file)
@@ -2343,6 +2343,15 @@ fNetworkSecurityPolicy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guin
 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
@@ -3127,6 +3136,8 @@ BACnetConfirmedServiceChoice[] = {
     { 29, "getEventInformation"},
     { 30, "subscribeCovPropertyMultiple"},
     { 31, "confirmedCovNotificationMultiple"},
+    { 32, "confirmedAuditNotification"},
+    { 33, "auditLogQuery"},
     { 0,  NULL}
 };
 
@@ -3182,6 +3193,7 @@ BACnetUnconfirmedServiceChoice [] = {
     { 9, "utcTimeSynchronization"},
     { 10, "writeGroup"},
     { 11, "unconfirmedCovNotificationMultiple"},
+    { 12, "unconfirmedAuditNotification"},
     { 0, NULL}
 };
 
@@ -3247,6 +3259,9 @@ BACnetObjectType [] = {
     { 57, "elevator-group"},
     { 58, "escalator"},
     { 59, "lift"},
+    { 60, "staging"},
+    { 61, "audit-log"},
+    { 62, "audit-reporter"},
     { 0,  NULL}
 /* Enumerated values 0-127 are reserved for definition by ASHRAE.
    Enumerated values 128-1023 may be used by others subject to
@@ -4149,6 +4164,20 @@ BACnetPropertyIdentifier [] = {
     { 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"},
     { 0,   NULL}
 /* Enumerated values 0-511 are reserved for definition by ASHRAE.
    Enumerated values 512-4194303 may be used by others subject to
@@ -4747,9 +4776,69 @@ BACnetAccumulatorStatus [] = {
     { 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 (manually) transferred from
  * http://www.bacnet.org/VendorID/BACnet Vendor IDs.htm
- * Version: "As of December 07, 2017"
+ * Version: "As of August 31, 2018"
  */
 
 static const value_string
@@ -5792,6 +5881,65 @@ BACnetVendorIdentifiers [] = {
     { 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 Buertsch AG" },
+    { 1046, "bGrid" },
+    { 1047, "MDJ Software Pty Ltd" },
+    { 1048, "Dimonoff, Inc." },
+    { 1049, "Edomo Systems" },
+    { 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" },
+    { 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 Automacao 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 Hrebec 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" },
     {    0, NULL }
 };
 static value_string_ext BACnetVendorIdentifiers_ext = VALUE_STRING_EXT_INIT(BACnetVendorIdentifiers);
@@ -7229,6 +7377,16 @@ fPropertyAccessResult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
   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;
@@ -7240,6 +7398,8 @@ fPropertyAccessResult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
     switch (tag_no) {
     case 0: /* objectIdentifier */
         offset = fObjectIdentifier(tvb, pinfo, tree, offset);
+        /* 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);
@@ -7249,9 +7409,14 @@ fPropertyAccessResult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
         break;
     case 3: /* deviceIdentifier */
         offset = fObjectIdentifier(tvb, pinfo, tree, offset);
+        /* 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)) {
@@ -7262,6 +7427,9 @@ fPropertyAccessResult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
         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;
@@ -7270,6 +7438,9 @@ fPropertyAccessResult(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
     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;
 }
 
@@ -8045,7 +8216,9 @@ fAbstractSyntaxNType(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
             offset = fClientCOV(tvb, pinfo, tree, offset);
             break;
         case 131:  /* log-buffer */
-            if ( object_type == 25 )
+            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);
@@ -8442,6 +8615,33 @@ fAbstractSyntaxNType(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
         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 85:  /* present-value */
             if ( object_type == 11 )    /* group object handling of present-value */
@@ -11245,6 +11445,312 @@ fNameValueCollection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
     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);
+            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)
+{
+    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: /* limit */
+            offset = fRealTag(tvb, pinfo, tree, offset, "limit: ");
+            break;
+        case 1: /* values */
+            offset = fBitStringTag(tvb, pinfo, tree, offset, "values: ");
+            break;
+        case 2: /* deadband */
+            offset = fRealTag(tvb, pinfo, tree, offset, "deadband: ");
+            break;
+        default:
+            break;
+        }
+        if (offset <= lastoffset) break;     /* nothing happened, exit loop */
+    }
+    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);
+            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);
+            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)
 {
@@ -12099,6 +12605,270 @@ fVtDataAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
     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);
+            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);
+            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  = fEnumeratedTagSplit(tvb, pinfo, tree, offset,
+                  "target-operation: ", BACnetAuditOperation, 64);
+            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);
+            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);
+            break;
+        case 3: /* source-operation */
+            offset  = fEnumeratedTagSplit(tvb, pinfo, tree, offset,
+                  "source-operation: ", BACnetAuditOperation, 64);
+            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);
+            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(subtree, 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);
+            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
 fAuthenticateRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
 {
@@ -13330,6 +14100,12 @@ fConfirmedServiceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gu
     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;
     }
@@ -13385,6 +14161,9 @@ fConfirmedServiceAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint
     case 29:
         offset = fGetEventInformationACK(tvb, pinfo, tree, offset);
         break;
+    case 33:
+        offset = fAuditLogQueryAck(tvb, pinfo, tree, offset);
+        break;
     default:
         return offset;
     }
@@ -13504,6 +14283,9 @@ fUnconfirmedServiceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     case 11:
         offset = fUnconfirmedCOVNotificationMultipleRequest(tvb, pinfo, tree, offset);
         break;
+    case 12:
+        offset = fUnconfirmedAuditNotificationRequest(tvb, pinfo, tree, offset);
+        break;
     default:
         break;
     }