summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonnie Sahlberg <ronnie_sahlberg@ozemail.com.au>2005-04-26 08:03:22 +0000
committerRonnie Sahlberg <ronnie_sahlberg@ozemail.com.au>2005-04-26 08:03:22 +0000
commit0f66df8509835e499db8cad904b7e63e9996d2e3 (patch)
tree5be652a9884bc50fbb2c0cfa3fc82b976265a838
parent5c5f1fd4e601decf5dc636f34738b3f6b357cb51 (diff)
downloadwireshark-0f66df8509835e499db8cad904b7e63e9996d2e3.tar.gz
BACAPP updates
svn path=/trunk/; revision=14188
-rw-r--r--epan/Makefile.nmake1
-rw-r--r--epan/dissectors/packet-bacapp.c5725
-rwxr-xr-xepan/dissectors/packet-bacapp.h2049
3 files changed, 7128 insertions, 647 deletions
diff --git a/epan/Makefile.nmake b/epan/Makefile.nmake
index 96a0335cca..20cae5121f 100644
--- a/epan/Makefile.nmake
+++ b/epan/Makefile.nmake
@@ -24,6 +24,7 @@ libethereal_LIBS = \
$(NETTLE_LIBS) \
$(ZLIB_LIBS) \
$(NET_SNMP_DIR)\win32\lib\release\netsnmp.lib \
+ $(ICONV_DIR)\lib\iconv.lib \
ftypes\ftypes.lib \
dfilter\dfilter.lib \
dissectors\dissectors.lib
diff --git a/epan/dissectors/packet-bacapp.c b/epan/dissectors/packet-bacapp.c
index 7f84585e75..766e630c9b 100644
--- a/epan/dissectors/packet-bacapp.c
+++ b/epan/dissectors/packet-bacapp.c
@@ -2,6 +2,7 @@
* Routines for BACnet (APDU) dissection
* Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
* Enhanced by Steve Karg, 2005, <skarg@users.sourceforge.net>
+ * Enhanced by Herbert Lischka, 2005, <lischka@kieback-peter.de>, Berlin
*
* $Id$
*
@@ -26,380 +27,5021 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "packet-bacapp.h"
+
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <glib.h>
-
-#include <epan/packet.h>
-
-// 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
-
-static const value_string bacapp_type_names[] = {
- { BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST, "Confirmed-Request" },
- { BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST, "Unconfirmed-Request" },
- { BACAPP_TYPE_SIMPLE_ACK, "SimpleACK" },
- { BACAPP_TYPE_COMPLEX_ACK, "ComplexACK" },
- { BACAPP_TYPE_SEGMENT_ACK, "SegmentACK" },
- { BACAPP_TYPE_ERROR, "Error" },
- { BACAPP_TYPE_REJECT, "Reject" },
- { BACAPP_TYPE_ABORT, "Abort" },
- { 0, NULL }
-};
-static const char *bacapp_unknown_str = "unknown";
static const char *bacapp_unknown_service_str = "unknown service";
-static const value_string bacapp_confirmed_service_names[] = {
- { 0, "Acknowledge-Alarm" },
- { 1, "COV-Notification" },
- { 2, "Event-Notification" },
- { 3, "Get-Alarm-Summary" },
- { 4, "Get-Enrollment-Summary" },
- { 5, "Subscribe-COV" },
- { 6, "Atomic-Read-File" },
- { 7, "Atomic-Write-File" },
- { 8, "Add-List-Element" },
- { 9, "Remove-List-Element" },
- { 10, "Create-Object" },
- { 11, "Delete-Object" },
- { 12, "Read-Property" },
- { 13, "Read-Property-Conditional" },
- { 14, "Read-Property-Multiple" },
- { 15, "Write-Property" },
- { 16, "Write-Property-Multiple" },
- { 17, "Device-Communication-Control" },
- { 18, "Private-Transfer" },
- { 19, "Text-Message" },
- { 20, "Reinitialize-Device" },
- { 21, "VT-Open" },
- { 22, "VT-Close" },
- { 23, "VT-Data" },
- { 24, "Authenticate" },
- { 25, "Request-Key" },
- { 26, "Read-Range" },
- { 27, "Life-Safety_Operation" },
- { 28, "Subscribe-COV-Property" },
- { 29, "Get-Event-Information" },
- { 0, NULL }
-};
-
-#define SERVICE_UNCONFIRMED_I_AM 0
-#define SERVICE_UNCONFIRMED_I_HAVE 1
-#define SERVICE_UNCONFIRMED_COV_NOTIFICATION 2
-#define SERVICE_UNCONFIRMED_EVENT_NOTIFICATION 3
-#define SERVICE_UNCONFIRMED_PRIVATE_TRANSFER 4
-#define SERVICE_UNCONFIRMED_TEXT_MESSAGE 5
-#define SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION 6
-#define SERVICE_UNCONFIRMED_WHO_HAS 7
-#define SERVICE_UNCONFIRMED_WHO_IS 8
-#define SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION 9
-/* Other services to be added as they are defined.
- All choice values in this production are reserved
- for definition by ASHRAE.
- Proprietary extensions are made by using the
- UnconfirmedPrivateTransfer service. See Clause 23.
-*/
-#define MAX_BACNET_UNCONFIRMED_SERVICE 10
-
-static const value_string bacapp_unconfirmed_service_names[] = {
- { SERVICE_UNCONFIRMED_I_AM, "I-Am" },
- { SERVICE_UNCONFIRMED_I_HAVE, "I-Have" },
- { SERVICE_UNCONFIRMED_COV_NOTIFICATION, "COV-Notification" },
- { SERVICE_UNCONFIRMED_EVENT_NOTIFICATION, "Event-Notification" },
- { SERVICE_UNCONFIRMED_PRIVATE_TRANSFER, "Private-Transfer" },
- { SERVICE_UNCONFIRMED_TEXT_MESSAGE, "Text-Message" },
- { SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION, "Time-Synchronization" },
- { SERVICE_UNCONFIRMED_WHO_HAS, "Who-Has" },
- { SERVICE_UNCONFIRMED_WHO_IS, "Who-Is" },
- { SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION, "UTC-Time-Synchronization" },
- { 0, NULL }
-};
-
-static const char*
-bacapp_reject_reason_name (guint8 bacapp_reason){
- static const char *reason_names[] = {
- "Other",
- "Buffer Overflow",
- "Inconsistent Parameters",
- "Invalid Parameter Data Type",
- "Invalid Tag",
- "Missing Required Parameter",
- "Parameter Out of Range",
- "Too Many Arguments",
- "Undefined Enumeration",
- "Unrecognized Service"
- };
- if (bacapp_reason < 10)
- return reason_names[bacapp_reason];
- else if (bacapp_reason < 64)
- return "Reserved for Use by ASHRAE";
-
- return "Vendor Proprietary Reason";
-}
-
-static const char*
-bacapp_abort_reason_name (guint8 bacapp_reason){
- static const char *reason_names[] = {
- "Other",
- "Buffer Overflow",
- "Invalid APDU in this State",
- "Preempted by Higher Priority Task",
- "Segmentation Not Supported"
- };
- if (bacapp_reason < 5)
- return reason_names[bacapp_reason];
- else if (bacapp_reason < 64)
- return "Reserved for Use by ASHRAE";
+static const value_string
+BACnetTypeName[] = {
+ {0, "Confirmed-Request "},
+ {1, "Unconfirmed-Request "},
+ {2, "SimpleACK "},
+ {3, "ComplexACK "},
+ {4, "SegmentACK "},
+ {5, "Error "},
+ {6, "Reject "},
+ {7, "Abort "},
+ {0, NULL }
+};
+
+static const true_false_string segments_follow = {
+ "Segmented Request",
+ "Unsegemented Request"
+};
+
+static const true_false_string more_follow = {
+ "More Segments Follow",
+ "No More Segments Follow"
+};
+
+static const true_false_string segmented_accept = {
+ "Segmented Response accepted",
+ "Segmented Response not accepted"
+};
+
+static const true_false_string
+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 Ethernet II 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"},
+ {10,"reserved by ASHRAE"},
+ {11,"reserved by ASHRAE"},
+ {12,"reserved by ASHRAE"},
+ {13,"reserved by ASHRAE"},
+ {14,"reserved by ASHRAE"},
+ {15,"reserved by ASHRAE"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetTagNumber [] = {
+ {0,"Null"},
+ {1,"Boolean"},
+ {2,"Unsigned Integer"},
+ {3,"Signed Integer (2's complement notation)"},
+ {4,"Real (ANSI/IEE-754 floating point)"},
+ {5,"Double (ANSI/IEE-754 double precision floating point)"},
+ {6,"Octet String"},
+ {7,"Character String"},
+ {8,"Bit String"},
+ {9,"Enumerated"},
+ {10,"Date"},
+ {11,"Time"},
+ {12,"BACnetObjectIdentifier"},
+ {13,"reserved by ASHRAE"},
+ {14,"reserved by ASHRAE"},
+ {15,"reserved by ASHRAE"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetAction [] = {
+ {0,"direct"},
+ {1,"reverse"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetFileAccessMethod [] = {
+ {0,"record-access"},
+ {1,"stream-access"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetAbortReason [] = {
+ {0,"other"},
+ {1,"buffer-overflow"},
+ {2,"invalid-apdu-in-this-state"},
+ {3,"preempted-by-higher-priority-task"},
+ {4,"segmentation-not-supported"},
+ {5,"reserved by ASHRAE"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetLifeSafetyMode [] = {
+ {0,"off"},
+ {1,"on"},
+ {2,"test"},
+ {3,"manned"},
+ {4,"unmanned"},
+ {5,"armed"},
+ {6,"disarmed"},
+ {7,"prearmed"},
+ {8,"slow"},
+ {9,"fast"},
+ {10,"disconnected"},
+ {11,"enabledt"},
+ {12,"disabled"},
+ {13,"atomic-release-disabled"},
+ {14,"default"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetLifeSafetyOperation [] = {
+ {0,"none"},
+ {1,"silence"},
+ {2,"silence-audible"},
+ {3,"silence-visual"},
+ {4,"reset"},
+ {5,"reset-alarm"},
+ {6,"reset-fault"},
+ {7,"reserved by ASHRAE"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetLimitEnable [] = {
+ {0,"lowLimitEnable"},
+ {1,"highLimitEnable"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetLifeSafetyState [] = {
+ {0,"quiet"},
+ {1,"pre-alarm"},
+ {2,"alarm"},
+ {3,"fault"},
+ {4,"fault-pre-alarm"},
+ {5,"fault-alarm"},
+ {6,"not-ready"},
+ {7,"active"},
+ {8,"tamper"},
+ {9,"test-alarm"},
+ {10,"test-active"},
+ {11,"test-fault"},
+ {12,"test-fault-alarm"},
+ {13,"holdup"},
+ {14,"duress"},
+ {15,"tamper-alarm"},
+ {16,"abnormal"},
+ {17,"emergency-power"},
+ {18,"delayed"},
+ {19,"blocked"},
+ {20,"local-alarm"},
+ {21,"general-alarm"},
+ {22,"supervisory"},
+ {23,"test-supervisory"},
+ {256,"not known"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetConfirmedServiceChoice [] = {
+ {0,"acknowledgeAlarm"},
+ {1,"confirmedCOVNotification"},
+ {2,"confirmedEventNotification"},
+ {3,"getAlarmSummary"},
+ {4,"getEnrollmentSummary"},
+ {5,"subscribeCOV"},
+ {6,"atomicReadFile"},
+ {7,"atomicWriteFile"},
+ {8,"addListElement"},
+ {9,"removeListElement"},
+ {10,"createObject"},
+ {11,"deleteObject"},
+ {12,"readProperty"},
+ {13,"readPropertyConditional"},
+ {14,"readPropertyMultiple"},
+ {15,"writeProperty"}, /* 15 */
+ {16,"writePropertyMultiple"},
+ {17,"deviceCommunicationControl"},
+ {18,"confirmedPrivateTransfer"},
+ {19,"confirmedTextMessage"},
+ {20,"reinitializeDevice"},
+ {21,"vtOpen"},
+ {22,"vtClose"},
+ {23,"vtData"},
+ {24,"authenticate"},
+ {25,"requestKey"}, /* 25 */
+ {26,"readRange"},
+ {27,"lifeSafetyOperation"},
+ {28,"subscribeCOVProperty"},
+ {29,"getEventInformation"},
+ {30,"reserved by ASHRAE"},
+ {0, NULL}
+};
+
+static const value_string
+BACnetReliability [] = {
+ {0,"no-fault-detected"},
+ {1,"no-sensor"},
+ {2,"over-range"},
+ {3,"under-range"},
+ {4,"open-loop"},
+ {5,"shorted-loop"},
+ {6,"no-output"},
+ {7,"unreliable-other"},
+ {8,"process-error"},
+ {9,"multi-state-fault"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetUnconfirmedServiceChoice [] = {
+ {0,"i-Am"},
+ {1,"i-Have"},
+ {2,"unconfirmedCOVNotification"},
+ {3,"unconfirmedEventNotification"},
+ {4,"unconfirmedPrivateTransfer"},
+ {5,"unconfirmedTextMessage"},
+ {6,"timeSynchronization"},
+ {7,"who-Has"},
+ {8,"who-Is"},
+ {9,"utcTimeSynchonization"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetUnconfirmedServiceRequest [] = {
+ {0,"i-Am-Request"},
+ {1,"i-Have-Request"},
+ {2,"unconfirmedCOVNotification-Request"},
+ {3,"unconfirmedEventNotification-Request"},
+ {4,"unconfirmedPrivateTransfer-Request"},
+ {5,"unconfirmedTextMessage-Request"},
+ {6,"timeSynchronization-Request"},
+ {7,"who-Has-Request"},
+ {8,"who-Is-Request"},
+ {9,"utcTimeSynchonization-Request"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetObjectType [] = {
+ {0,"analog-input object"},
+ {1,"analog-output object"},
+ {2,"analog-value object"},
+ {3,"binary-input object"},
+ {4,"binary-output object"},
+ {5,"binary-value object"},
+ {6,"calendar object"},
+ {7,"command object"},
+ {8,"device object"},
+ {9,"event-enrollment object"},
+ {10,"file object"},
+ {11,"group object"},
+ {12,"loop object"},
+ {13,"multi-state-input object"},
+ {14,"multi-state-output object"},
+ {15,"notification-class object"},
+ {16,"program object"},
+ {17,"schedule object"},
+ {18,"averaging object"},
+ {19,"multi-state-value object"},
+ {20,"trend-log object"},
+ {21,"life-safety-point object"},
+ {22,"life-safety-zone object"},
+ {0, NULL}
+};
+
+static const value_string
+BACnetUnits [] = {
+ {0,"Sq Meters"},
+ {1,"Sq Feet"},
+ {2,"Milliamperes"},
+ {3,"Amperes"},
+ {4,"Ohms"},
+ {5,"Volts"},
+ {6,"Kilovolts"},
+ {7,"Megavolts"},
+ {8,"Volt Amperes"},
+ {9,"Kilovolt Amperes"},
+ {10,"Megavolt Amperes"},
+ {11,"Volt Amperes Reactive"},
+ {12,"Kilovolt Amperes Reactive"},
+ {13,"Megavolt Amperes Ractive"},
+ {14,"Degrees Phase"},
+ {15,"Power Factor"},
+ {16,"Joules"},
+ {17,"Kilojoules"},
+ {18,"Watt Hours"},
+ {19,"Kilowatt Hours"},
+ {20,"BTUs"},
+ {21,"Therms"},
+ {22,"Ton Hours"},
+ {23,"Joules Per Kg Dry Air"},
+ {24,"BTUs Per Pound Dry Air"},
+ {25,"Cycles Per Hour"},
+ {26,"Cycles Per Minute"},
+ {27,"Hertz"},
+ {28,"Gramms Of Water Per Kilogram Dry Air"},
+ {29,"Relative Humidity"},
+ {30,"Millimeters"},
+ {31,"Meters"},
+ {32,"Inches"},
+ {33,"Feed"},
+ {34,"Watts Per Sq Foot"},
+ {35,"Watts Per Sq meter"},
+ {36,"Lumens"},
+ {37,"Lux"},
+ {38,"Foot Candels"},
+ {39,"Kilograms"},
+ {40,"Pounds Mass"},
+ {41,"Tons"},
+ {42,"Kgs per Second"},
+ {43,"Kgs Per Minute"},
+ {44,"Kgs Per Hour"},
+ {45,"Pounds Mass Per Minute"},
+ {46,"Pounds Mass Per Hour"},
+ {47,"Watt"},
+ {48,"Kilowatts"},
+ {49,"Megawatts"},
+ {50,"BTUs Per Hour"},
+ {51,"Horsepower"},
+ {52,"Tons Refrigeration"},
+ {53,"Pascals"},
+ {54,"Kilopascals"},
+ {55,"Bars"},
+ {56,"Pounds Force Per Square Inch"},
+ {57,"Centimeters Of Water"},
+ {58,"Inches Of Water"},
+ {59,"Millimeters Of Mercury"},
+ {60,"Centimeters Of Mercury"},
+ {61,"Inches Of Mercury"},
+ {62,"Degrees Celsius"},
+ {63,"Degress Kelvin"},
+ {64,"Degrees Fahrenheit"},
+ {65,"Degree Days Celsius"},
+ {66,"Degree Days Fahrenheit"},
+ {67,"Years"},
+ {68,"Months"},
+ {69,"Weeks"},
+ {70,"Days"},
+ {71,"Hours"},
+ {72,"Minutes"},
+ {73,"Seconds"},
+ {74,"Meters Per Second"},
+ {75,"Kilometers Per Hour"},
+ {76,"Feed Per Second"},
+ {77,"Feet Per Minute"},
+ {78,"Miles Per Hour"},
+ {79,"Cubic Feet"},
+ {80,"Cubic Meters"},
+ {81,"Imperial Gallons"},
+ {82,"Liters"},
+ {83,"US Gallons"},
+ {84,"Cubic Feet Per Minute"},
+ {85,"Cubic Meters Per Second"},
+ {86,"Imperial Gallons Per Minute"},
+ {87,"Liters Per Second"},
+ {88,"Liters Per Minute"},
+ {89,"US Gallons Per Minute"},
+ {90,"Degrees Angular"},
+ {91,"Degrees Celsius Per Hour"},
+ {92,"Degrees Celsius Per Minute"},
+ {93,"Degrees Fahrenheit Per Hour"},
+ {94,"Degrees Fahrenheit Per Minute"},
+ {95,"No Units"},
+ {96,"Parts Per Million"},
+ {97,"Parts Per Billion"},
+ {98,"Percent"},
+ {99,"Pecent Per Second"},
+ {100,"Per Minute"},
+ {101,"Per Second"},
+ {102,"Psi Per Degree Fahrenheit"},
+ {103,"Radians"},
+ {104,"Revolutions Per Min"},
+ {105,"Currency1"},
+ {106,"Currency2"},
+ {107,"Currency3"},
+ {108,"Currency4"},
+ {109,"Currency5"},
+ {110,"Currency6"},
+ {111,"Currency7"},
+ {112,"Currency8"},
+ {113,"Currency9"},
+ {114,"Currency10"},
+ {115,"Sq Inches"},
+ {116,"Sq Centimeters"},
+ {117,"BTUs Per Pound"},
+ {118,"Centimeters"},
+ {119,"Pounds Mass Per Second"},
+ {120,"Delta Degrees Fahrenheit"},
+ {121,"Delta Degrees Kelvin"},
+ {122,"Kilohms"},
+ {123,"Megohms"},
+ {124,"Millivolts"},
+ {125,"Kilojoules Per Kg"},
+ {126,"Megajoules"},
+ {127,"Joules Per Degree Kelvin"},
+ {128,"Joules Per Kg Degree Kelvin"},
+ {129,"Kilohertz"},
+ {130,"Megahertz"},
+ {131,"Per Hour"},
+ {132,"Milliwatts"},
+ {133,"Hectopascals"},
+ {134,"Millibars"},
+ {135,"Cubic Meters Per Hour"},
+ {136,"Liters Per Hour"},
+ {137,"KWatt Hours Per Square Meter"},
+ {138,"KWatt Hours Per Square Foot"},
+ {139,"Megajoules Per Square Meter"},
+ {140,"Megajoules Per Square Foot"},
+ {141,"Watts Per Sq Meter Degree Kelvin"},
+ {142,"Cubic Feet Per Second"},
+ {143,"Percent Obstruction Per Foot"},
+ {144,"Percent Obstruction Per Meter"},
+ {256,"Kelvin Per Minute"},
+ {257,"Minute Per Kelvin"},
+ {258,"Kelvin Per Hour"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetErrorCode [] = {
+ {0,"other"},
+ {1,"authentication-failed"},
+ {2,"character-set-not-supported"},
+ {3,"configuration-in-progress"},
+ {4,"device-busy"},
+ {5,"file-access-denied"},
+ {6,"incompatible-security-levels"},
+ {7,"inconsistent-parameters"},
+ {8,"inconsistent-selection-criterion"},
+ {9,"invalid-data-type"},
+ {10,"invalid-file-access-method"},
+ {11,"invalid-file-start-position"},
+ {12,"invalid-operator-name"},
+ {13,"invalid-parameter-data-type"},
+ {14,"invalid-time-stamp"},
+ {15,"key-generation-error"},
+ {16,"missing-required-parameter"},
+ {17,"no-objects-of-specified-type"},
+ {18,"no-space-for-object"},
+ {19,"no-space-to-add-list-element"},
+ {20,"no-space-to-write-property"},
+ {21,"no-vt-sessions-available"},
+ {22,"property-is-not-a-list"},
+ {23,"object-deletion-not-permitted"},
+ {24,"object-identifier-already-exists"},
+ {25,"operational-problem"},
+ {26,"password-failure"},
+ {27,"read-access-denied"},
+ {28,"security-not-supported"},
+ {29,"service-request-denied"},
+ {30,"timeout"},
+ {31,"unknown-object"},
+ {32,"unknown-property"},
+ {33,"removed enumeration"},
+ {34,"unknown-vt-class"},
+ {35,"unknown-vt-session"},
+ {36,"unsupported-object-type"},
+ {37,"value-out-of-range"},
+ {38,"vt-session-already-closed"},
+ {39,"vt-session-termination-failure"},
+ {40,"write-access-denied"},
+ {41,"character-set-not-supported"},
+ {42,"invalid-array-index"},
+ {43,"cov-subscription-failed"},
+ {44,"not-cov-property"},
+ {45,"optional-functionaltity-not-supported"},
+ {46,"invalid-configuration-data"},
+ {47,"reserved by ASHRAE"},
+ {0, NULL}
+};
+
+static const value_string
+BACnetPropertyIdentifier [] = {
+ {0,"acked-transition"},
+ {1,"ack-required"},
+ {2,"action"},
+ {3,"action-text"},
+ {4,"active-text"},
+ {5,"active-vt-session"},
+ {6,"alarm-value"},
+ {7,"alarm-values"},
+ {8,"all"},
+ {9,"all-write-successfull"},
+ {10,"apdu-segment-timeout"},
+ {11,"apdu-timeout"},
+ {12,"application-software-version"},
+ {13,"archive"},
+ {14,"bias"},
+ {15,"change-of-state-count"},
+ {16,"change-of-state-time"},
+ {17,"notification-class"},
+ {18,"the property in this place was deleted"},
+ {19,"controlled-variable-reference"},
+ {20,"controlled-variable-units"},
+ {21,"controlled-variable-value"},
+ {22,"cov-increment"},
+ {23,"datelist"},
+ {24,"daylights-savings-status"},
+ {25,"deadband"},
+ {26,"derivative-constant"},
+ {27,"derivative-constant-units"},
+ {28,"description"},
+ {29,"description-of-halt"},
+ {30,"device-address-binding"},
+ {31,"device-type"},
+ {32,"effective-period"},
+ {33,"elapsed-active-time"},
+ {34,"error-limit"},
+ {35,"event-enable"},
+ {36,"event-state"},
+ {37,"event-type"},
+ {38,"exception-schedule"},
+ {39,"fault-values"},
+ {40,"feedback-value"},
+ {41,"file-access-method"},
+ {42,"file-size"},
+ {43,"file-type"},
+ {44,"firmware-revision"},
+ {45,"high-limit"},
+ {46,"inactive-text"},
+ {47,"in-progress"},
+ {48,"instance-of"},
+ {49,"integral-constant"},
+ {50,"integral-constant-units"},
+ {51,"issue-confirmed-notifications"},
+ {52,"limit-enable"},
+ {53,"list-of-group-members"},
+ {54,"list-of-object-property-references"},
+ {55,"list-of-session-keys"},
+ {56,"local-date"},
+ {57,"local-time"},
+ {58,"location"},
+ {59,"low-limit"},
+ {60,"manipulated-variable-reference"},
+ {61,"maximum-output"},
+ {62,"max-apdu-length-accepted"},
+ {63,"max-info-frames"},
+ {64,"max-master"},
+ {65,"max-pres-value"},
+ {66,"minimum-off-time"},
+ {67,"minimum-on-time"},
+ {68,"minimum-output"},
+ {69,"min-pres-value"},
+ {70,"model-name"},
+ {71,"modification-date"},
+ {72,"notify-type"},
+ {73,"number-of-APDU-retries"},
+ {74,"number-of-states"},
+ {75,"object-identifier"},
+ {76,"object-list"},
+ {77,"object-name"},
+ {78,"object-property-reference"},
+ {79,"object-type"},
+ {80,"optional"},
+ {81,"out-of-service"},
+ {82,"output-units"},
+ {83,"event-parameters"},
+ {84,"polarity"},
+ {85,"present-value"},
+ {86,"priority"},
+ {87,"priority-array"},
+ {88,"priority-for-writing"},
+ {89,"process-identifier"},
+ {90,"program-change"},
+ {91,"program-location"},
+ {92,"program-state"},
+ {93,"proportional-constant"},
+ {94,"proportional-constant-units"},
+ {95,"protocol-conformance-class"},
+ {96,"protocol-object-types-supported"},
+ {97,"protocol-services-supported"},
+ {98,"protocol-version"},
+ {99,"read-only"},
+ {100,"reason-for-halt"},
+ {101,"recipient"},
+ {102,"recipient-list"},
+ {103,"reliability"},
+ {104,"relinquish-default"},
+ {105,"required"},
+ {106,"resolution"},
+ {107,"segmentation-supported"},
+ {108,"setpoint"},
+ {109,"setpoint-reference"},
+ {110,"state-text"},
+ {111,"status-flags"},
+ {112,"system-status"},
+ {113,"time-delay"},
+ {114,"time-of-active-time-reset"},
+ {115,"time-of-state-count-reset"},
+ {116,"time-synchronization-recipients"},
+ {117,"units"},
+ {118,"update-interval"},
+ {119,"utc-offset"},
+ {120,"vendor-identifier"},
+ {121,"vendor-name"},
+ {122,"vt-class-supported"},
+ {123,"weekly-schedule"},
+ {124,"attempted-samples"},
+ {125,"average-value"},
+ {126,"buffer-size"},
+ {127,"client-cov-increment"},
+ {128,"cov-resubscription-interval"},
+ {129,"current-notify-time"},
+ {130,"event-time-stamp"},
+ {131,"log-buffer"},
+ {132,"log-device-object-property"},
+ {133,"log-enable"},
+ {134,"log-interval"},
+ {135,"maximum-value"},
+ {136,"minimum-value"},
+ {137,"notification-threshold"},
+ {138,"previous-notify-time"},
+ {139,"protocol-revision"},
+ {140,"records-since-notification"},
+ {141,"record-count"},
+ {142,"start-time"},
+ {143,"stop-time"},
+ {144,"stop-when-full"},
+ {145,"total-record-count"},
+ {146,"valid-samples"},
+ {147,"window-interval"},
+ {148,"window-samples"},
+ {149,"maximum-value-time-stamp"},
+ {150,"minimum-value-time-stamp"},
+ {151,"variance-value"},
+ {152,"active-cov-subscriptions"},
+ {153,"backup-failure-timeout"},
+ {154,"configuration-files"},
+ {155,"database-revision"},
+ {156,"direct-reading"},
+ {157,"last-restore-time"},
+ {158,"maintenance-required"},
+ {159,"member-of"},
+ {160,"mode"},
+ {161,"operation-expected"},
+ {162,"setting"},
+ {163,"silenced"},
+ {164,"tracking-value"},
+ {165,"zone-members"},
+ {166,"life-safety-alarm-values"},
+ {167,"max-segments-accepted"},
+ {168,"profile-name"},
+ {0, NULL}
+};
+
+static const value_string
+BACnetBinaryPV [] = {
+ {0,"inactive"},
+ {1,"active"},
+ {0,NULL}
+};
+
+
+static const value_string
+BACnetCharacterSet [] = {
+ {0,"ANSI X3.4"},
+ {1,"IBM/Microsoft DBCS"},
+ {2,"JIS C 6226"},
+ {3,"ISO 10646(UCS-4)"},
+ {4,"ISO 10646(UCS-2)"},
+ {5,"ISO 18859-1"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetStatusFlags [] = {
+ {0,"in-alarm"},
+ {1,"fault"},
+ {2,"overridden"},
+ {3,"out-of-service"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetMessagePriority [] = {
+ {0,"normal"},
+ {1,"urgent"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetAcknowledgementFilter [] = {
+ {0,"and"},
+ {1,"or"},
+ {2,"all"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetResultFlags [] = {
+ {0,"firstitem"},
+ {1,"lastitem"},
+ {2,"moreitems"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetRelationSpecifier [] = {
+ {0,"equal"},
+ {1,"not-equal"},
+ {2,"less-than"},
+ {3,"greater-than"},
+ {4,"less-than-or-equal"},
+ {5,"greater-than-or-equal"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetSelectionLogic [] = {
+ {0,"normal"},
+ {1,"urgent"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetEventStateFilter [] = {
+ {0,"offnormal"},
+ {1,"fault"},
+ {2,"normal"},
+ {3,"all"},
+ {4,"active"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetEventTransitionBits [] = {
+ {0,"to-offnormal"},
+ {1,"to-fault"},
+ {2,"to-normal"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetSegmentation [] = {
+ {0,"segmented-both"},
+ {1,"segmented-transmit"},
+ {2,"segmented-receive"},
+ {3,"no-segmentation"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetSilencedState [] = {
+ {0,"unsilenced"},
+ {1,"audible-silenced"},
+ {2,"visible-silenced"},
+ {3,"all-silenced"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetDeviceStatus [] = {
+ {0,"operational"},
+ {1,"operational-read-only"},
+ {2,"download-required"},
+ {3,"download-in-progress"},
+ {4,"non-operational"},
+ {5,"backup-in-progress"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetEnableDisable [] = {
+ {0,"enable"},
+ {1,"disable"},
+ {0,NULL}
+};
+
+static const value_string
+months [] = {
+ {1,"January" },
+ {2,"February" },
+ {3,"March" },
+ {4,"April" },
+ {5,"May" },
+ {6,"June" },
+ {7,"July" },
+ {8,"August" },
+ {9,"September" },
+ {10,"October" },
+ {11,"November" },
+ {12,"December" },
+ {255,"any month" },
+ {0,NULL }
+};
+
+static const value_string
+weekofmonth [] = {
+ {1,"days numbered 1-7" },
+ {2,"days numbered 8-14" },
+ {3,"days numbered 15-21" },
+ {4,"days numbered 22-28" },
+ {5,"days numbered 29-31" },
+ {6,"last 7 days of this month" },
+ {255,"any week of this month" },
+ {0,NULL }
+};
+
+static const value_string
+days [] = {
+ {1,"Monday" },
+ {2,"Tuesday" },
+ {3,"Wednesday" },
+ {4,"Thursday" },
+ {5,"Friday" },
+ {6,"Saturday" },
+ {7,"Sunday" },
+ {255,"any day of week" },
+ {0,NULL },
+};
+
+static const value_string
+BACnetErrorClass [] = {
+ {0,"device" },
+ {1,"object" },
+ {2,"property" },
+ {3,"resources" },
+ {4,"security" },
+ {5,"services" },
+ {6,"vt" },
+ {0,NULL },
+};
+
+static const value_string
+BACnetVTClass [] = {
+ {0,"default-terminal" },
+ {1,"ansi-x3-64" },
+ {2,"dec-vt52" },
+ {3,"dec-vt100" },
+ {4,"dec-vt200" },
+ {5,"hp-700-94" },
+ {6,"ibm-3130" },
+ {0,NULL },
+};
+
+static const value_string
+BACnetEventType [] = {
+ {0,"change-of-bitstring" },
+ {1,"change-of-state" },
+ {2,"change-of-value" },
+ {3,"command-failure" },
+ {4,"floating-limit" },
+ {5,"out-of-range" },
+ {6,"complex-event-type" },
+ {7,"buffer-ready" },
+ {8,"change-of-life-safety" },
+ {0,NULL },
+};
+
+static const value_string
+BACnetEventState [] = {
+ {0,"normal" },
+ {1,"fault" },
+ {2,"offnormal" },
+ {3,"high-limit" },
+ {4,"low-limit" },
+ {5,"life-safety-alarm" },
+ {0,NULL },
+};
+
+static const value_string
+BACnetLogStatus [] = {
+ {0,"log-disabled" },
+ {1,"buffer-purged" },
+ {0,NULL },
+};
+
+static const value_string
+BACnetMaintenance [] = {
+ {0,"none" },
+ {1,"periodic-test" },
+ {2,"need-service-operational" },
+ {3,"need-service-inoperative" },
+ {0,NULL },
+};
+
+static const value_string
+BACnetNotifyType [] = {
+ {0,"alarm" },
+ {1,"event" },
+ {2,"ack-notification" },
+ {0,NULL },
+};
+
+static const value_string
+BACnetServicesSupported [] = {
+ {0,"acknowledgeAlarm"},
+ {1,"confirmedCOVNotification"},
+ {2,"confirmedEventNotification"},
+ {3,"getAlarmSummary"},
+ {4,"getEnrollmentSummary"},
+ {5,"subscribeCOV"},
+ {6,"atomicReadFile"},
+ {7,"atomicWriteFile"},
+ {8,"addListElement"},
+ {9,"removeListElement"},
+ {10,"createObject"},
+ {11,"deleteObject"},
+ {12,"readProperty"},
+ {13,"readPropertyConditional"},
+ {14,"readPropertyMultiple"},
+ {15,"writeProperty"}, /* 15 */
+ {16,"writePropertyMultiple"},
+ {17,"deviceCommunicationControl"},
+ {18,"confirmedPrivateTransfer"},
+ {19,"confirmedTextMessage"},
+ {20,"reinitializeDevice"},
+ {21,"vtOpen"},
+ {22,"vtClose"},
+ {23,"vtData"},
+ {24,"authenticate"},
+ {25,"requestKey"}, /* 25 */
+ {26,"i-Am"},
+ {27,"i-Have"},
+ {28,"unconfirmedCOVNotification"},
+ {29,"unconfirmedEventNotification"},
+ {30,"unconfirmedPrivateTransfer"},
+ {31,"unconfirmedTextMessage"},
+ {32,"timeSynchronization"},
+ {33,"who-Has"},
+ {34,"who-Is"},
+ {35,"readRange"},
+ {36,"utcTimeSynchronization"},
+ {37,"lifeSafetyOperation"},
+ {38,"subscribeCOVProperty"},
+ {39,"getEventInformation"},
+ {40,"reserved by ASHRAE"},
+ {0, NULL}
+};
+
+static const value_string
+BACnetPropertyStates [] = {
+ {0,"boolean-value"},
+ {1,"binary-value"},
+ {2,"event-type"},
+ {3,"polarity"},
+ {4,"program-change"},
+ {5,"program-state"},
+ {6,"reason-for-halt"},
+ {7,"reliability"},
+ {8,"state"},
+ {9,"system-status"},
+ {10,"units"},
+ {11,"unsigned-value"},
+ {12,"life-safety-mode"},
+ {13,"life-safety-state"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetProgramError [] = {
+ {0,"normal"},
+ {1,"load-failed"},
+ {2,"internal"},
+ {3,"program"},
+ {4,"other"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetProgramRequest [] = {
+ {0,"ready"},
+ {1,"load"},
+ {2,"run"},
+ {3,"halt"},
+ {4,"restart"},
+ {4,"unload"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetProgramState [] = {
+ {0,"idle"},
+ {1,"loading"},
+ {2,"running"},
+ {3,"waiting"},
+ {4,"halted"},
+ {4,"unloading"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetReinitializedStateOfDevice [] = {
+ {0,"coldstart"},
+ {1,"warmstart"},
+ {2,"startbackup"},
+ {3,"endbackup"},
+ {4,"startrestore"},
+ {5,"endrestore"},
+ {6,"abortrestore"},
+ {0,NULL}
+};
+
+static const value_string
+BACnetPolarity [] = {
+ {0,"normal"},
+ {1,"reverse"},
+ {0,NULL}
+};
+
+
+static int proto_bacapp = -1;
+static int hf_bacapp_type = -1;
+static int hf_bacapp_SEG = -1;
+static int hf_bacapp_MOR = -1;
+static int hf_bacapp_SA = -1;
+static int hf_bacapp_response_segments = -1;
+static int hf_bacapp_max_adpu_size = -1;
+static int hf_bacapp_invoke_id = -1;
+static int hf_bacapp_objectType = -1;
+static int hf_bacapp_instanceNumber = -1;
+static int hf_bacapp_sequence_number = -1;
+static int hf_bacapp_window_size = -1;
+static int hf_bacapp_service = -1;
+static int hf_bacapp_NAK = -1;
+static int hf_bacapp_SRV = -1;
+static int hf_BACnetRejectReason = -1;
+static int hf_BACnetAbortReason = -1;
+static int hf_BACnetTagNumber = -1;
+static int hf_BACnetTagClass = -1;
+static int hf_bacapp_tag_lvt = -1;
+static int hf_bacapp_tag_ProcessId = -1;
+static int hf_bacapp_tag_initiatingObjectType = -1;
+static int hf_bacapp_vpart = -1;
+
+static int hf_bacapp_uservice = -1;
+
+
+static gint ett_bacapp = -1;
+static gint ett_bacapp_control = -1;
+static gint ett_bacapp_tag = -1;
+static gint ett_bacapp_list = -1;
+static gint ett_bacapp_value = -1;
+
+static dissector_handle_t data_handle;
- return "Vendor Proprietary Reason";
+static gint32 propertyIdentifier = -1;
+
+static guint8 bacapp_flags = 0;
+static guint8 bacapp_seq = 0;
+
+static guint
+fTagNo (tvbuff_t *tvb, guint offset)
+{
+ return (guint)(tvb_get_guint8(tvb, offset) >> 4);
}
-/* from clause 20.1.2.4 max-segments-accepted
- returns the decoded value
-
- max-segments-accepted
- B'000' Unspecified number of segments accepted.
- B'001' 2 segments accepted.
- B'010' 4 segments accepted.
- B'011' 8 segments accepted.
- B'100' 16 segments accepted.
- B'101' 32 segments accepted.
- B'110' 64 segments accepted.
- B'111' Greater than 64 segments accepted.
-*/
-static guint8 decode_max_segs(guint8 octet)
-{
- guint8 max_segs = 0;
-
- switch (octet & 0xF0)
- {
- case 0:
- max_segs = 0;
+static guint
+fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* class_tag, guint32 *lvt)
+{
+ guint8 tmp;
+ guint offs = 1;
+
+ tmp = tvb_get_guint8(tvb, offset);
+ *class_tag = tmp & 0x08; /* 0 = Application Tag, 1 = Context Specific Tag */
+ *lvt = tmp & 0x07;
+ *tag_no = tmp >> 4;
+ if (*tag_no == 15) { /* B'1111' because of extended tagnumber */
+ *tag_no = tvb_get_guint8(tvb, offset + offs++);
+ }
+ if (*lvt == 5) { /* length is more than 4 Bytes */
+ *lvt = tvb_get_guint8(tvb, offset + offs++);
+ if (*lvt == 254) { /* length is encoded with 16 Bits */
+ *lvt = tvb_get_guint8(tvb, offset + offs++);
+ *lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
+ } else {
+ if (*lvt == 255) { /* length is encoded with 32 Bits */
+ *lvt = tvb_get_guint8(tvb, offset + offs++);
+ *lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
+ *lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
+ *lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
+ }
+ }
+ }
+
+ return offs;
+}
+
+static guint
+fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+ guint8 tmp, i;
+ guint64 val = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint offs;
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ for (i = 0; i < min(lvt,8); i++) {
+ tmp = tvb_get_guint8(tvb, offset+offs+i);
+ val = (val << 8) + tmp;
+ }
+ proto_tree_add_text(tree, tvb, offset, min(lvt,8)+offs, "%s(Unsigned) %" PRIu64, LABEL(label), val);
+ return offset+offs+min(lvt,8);
+}
+
+static guint
+fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+ guint8 tmp, i;
+ guint64 val = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint offs;
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ for (i = 0; i < min(lvt,8); i++) {
+ tmp = tvb_get_guint8(tvb, offset+offs+i);
+ val = (val << 8) + tmp;
+ }
+ proto_tree_add_text(tree, tvb, offset, min(lvt,8)+offs, "%s(Signed) %" PRId64, LABEL(label), (gint64) val);
+ return offset+offs+min(lvt,8);
+}
+
+static guint
+fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint8 tmp, i;
+ guint32 val = 0, lvt;
+ guint8 tag_no, class_tag;
+ guint offs;
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ for (i = 0; i < min(lvt, 4); i++) {
+ tmp = tvb_get_guint8(tvb, offset+offs+i);
+ val = (val << 8) + tmp;
+ }
+
+ proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, offset, offs+i, val);
+ return offset+offs+i;
+}
+
+static guint
+fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+ guint8 tmp, i;
+ guint val = 0;
+ guint32 lvt;
+ guint8 tag_no, class_tag;
+ guint offs;
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ for (i = 0; i < min(lvt, 4); i++) {
+ tmp = tvb_get_guint8(tvb, offset+offs+i);
+ val = (val << 8) + tmp;
+ }
+ proto_tree_add_text(tree, tvb, offset, i+offs, "%s (hh.mm.ss): %d.%02d.%02d%s", LABEL(label), (val / 3600), ((val % 3600) / 60), (val % 60), val == 0 ? " (indefinite)" : "");
+ return offset+offs+i;
+}
+
+static guint
+fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint32 month, weekOfMonth, dayOfWeek;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint offs;
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ month = tvb_get_guint8(tvb, offset+offs);
+ weekOfMonth = tvb_get_guint8(tvb, offset+offs+1);
+ dayOfWeek = tvb_get_guint8(tvb, offset+offs+2);
+ proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s %s, %s",
+ val_to_str(month, months, "month (%d) not found"),
+ val_to_str(weekOfMonth, weekofmonth, "week of month (%d) not found"),
+ val_to_str(dayOfWeek, days, "day of week (%d) not found"));
+ return offset+offs+lvt;
+}
+
+static guint
+fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+ guint32 year, month, day, weekday;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint offs;
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ year = tvb_get_guint8(tvb, offset+offs) + 1900;
+ month = tvb_get_guint8(tvb, offset+offs+1);
+ day = tvb_get_guint8(tvb, offset+offs+2);
+ weekday = tvb_get_guint8(tvb, offset+offs+3);
+ if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
+ proto_tree_add_text(tree, tvb, offset, lvt+offs, "%sany", LABEL(label));
+ else
+ proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%s %d, %d, (Day of Week = %s)",
+ LABEL(label), val_to_str(month, months, "month (%d) not found"),
+ day, year, val_to_str(weekday, days, "(%d) not found"));
+ return offset+offs+lvt;
+}
+
+static guint
+fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+ guint32 year, month, day, weekday, lvt;
+ guint8 tag_no, class_tag;
+ guint offs;
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ year = tvb_get_guint8(tvb, offset+offs);
+ month = tvb_get_guint8(tvb, offset+offs+1);
+ day = tvb_get_guint8(tvb, offset+offs+2);
+ weekday = tvb_get_guint8(tvb, offset+offs+3);
+ if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
+ proto_tree_add_text(tree, tvb, offset, lvt+offs, "%sany", LABEL(label));
+ else
+ proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%d:%02d:%02d.%d %s = %02d:%02d:%02d.%d", LABEL(label), year > 12 ? year -12 : year, month, day, weekday, year > 12 ? "P.M." : "A.M.", year, month, day, weekday);
+ return offset+offs+lvt;
+}
+
+static guint
+fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ if (label != NULL) {
+ tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", LABEL(label));
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ }
+ offset = fDate (tvb,subtree,offset,"Date: ");
+ return fTime (tvb,subtree,offset,"Time: ");
+}
+
+static guint
+fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag, but not for me */
+ return offset;
+ }
+ offset = fTime (tvb,tree,offset,"Time: ");
+ offset = fApplicationTypes (tvb,tree,offset, "Value: ", NULL);
+ }
+ return offset;
+}
+
+static guint
+fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* Date */
+ offset = fDate (tvb, tree, offset, "Date: ");
+ break;
+ case 1: /* dateRange */
+ offset = fDateRange (tvb, tree, offset);
+ break;
+ case 2: /* BACnetWeekNDay */
+ offset = fWeekNDay (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset < tvb_reported_length(tvb)) { /* don't loop, it's a CHOICE */
+
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* time */
+ offset = fTime (tvb, tree, offset, "timestamp: ");
+ break;
+ case 1: /* sequenceNumber */
+ offset = fUnsignedTag (tvb, tree, offset, "sequence Number: ");
+ break;
+ case 2: /* dateTime */
+ offset = fDateTime (tvb, tree, offset, "timestamp: ");
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* setpointReference */
+ offset = fObjectPropertyReference (tvb,tree,offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+
+static guint
+fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset < tvb_reported_length(tvb)) {
+ offset = fApplicationTypes (tvb,tree,offset, "increment: ",NULL);
+ }
+ return offset;
+}
+
+static guint
+fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset < tvb_reported_length(tvb)) {
+ offset = fApplicationTypes (tvb,tree,offset, "valid Days: ", days);
+ offset = fTime (tvb,tree,offset,"from time: ");
+ offset = fTime (tvb,tree,offset,"to time: ");
+ offset = fRecipient (tvb,tree,offset);
+ offset = fProcessId (tvb,tree,offset);
+ offset = fApplicationTypes (tvb,tree,offset,"issue confirmed notifications: ", NULL);
+ offset = fApplicationTypes (tvb,tree,offset,"transitions: ", BACnetEventTransitionBits);
+ }
+ return offset;
+}
+
+static guint
+fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, guint32 lvt)
+{
+ guint8 *str_val;
+ guint len;
+
+ if ((lvt == 0) || ((lvt+offset) > tvb_length(tvb)))
+ lvt = tvb_length(tvb) - offset;
+
+ proto_tree_add_text(tree, tvb, offset, lvt, "[displayed OctetString with %d Bytes:] %s", lvt, LABEL(label));
+
+ do {
+ len = min (lvt, 200);
+ str_val = tvb_get_string(tvb, offset, len);
+ proto_tree_add_text(tree, tvb, offset, len, "%s", str_val);
+ g_free(str_val);
+ lvt -= len;
+ offset += len;
+ } while (lvt > 0);
+
+ if (tvb_length(tvb) < tvb_reported_length(tvb)) {
+ proto_tree_add_text(tree, tvb, offset, tvb_reported_length(tvb) - tvb_length(tvb), "[Frame is %d Bytes shorter than expected]", tvb_reported_length(tvb) - tvb_length(tvb));
+ str_val = tvb_get_string(tvb, offset, 1);
+ g_free(str_val);
+ }
+ return offset;
+}
+
+static guint
+fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint offs;
+
+ offset = fUnsignedTag (tvb, tree, offset, "network-number");
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (lvt == 0) {
+ proto_tree_add_text(tree, tvb, offset, offs, "mac-address: broadcast");
+ offset += offs;
+ } else
+ offset = fOctetString (tvb, tree, offset, "mac-address: ", lvt);
+ return offset;
+}
+
+static guint
+fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ offset = fOctetString (tvb,tree,offset,"session key: ", 8);
+ return fAddress (tvb,tree,offset);
+}
+
+static guint
+fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint offs;
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ proto_tree_add_item(tree, hf_bacapp_objectType, tvb, offset+offs, 4, FALSE);
+ proto_tree_add_item(tree, hf_bacapp_instanceNumber, tvb, offset+offs, 4, FALSE);
+
+ return offset+offs+4;
+}
+
+static guint
+fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* device */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 1: /* address */
+ offset = fAddress (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* recipient */
+ offset = fRecipient (tvb, tree, offset);
+ break;
+ case 1: /* processId */
+ offset = fProcessId (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ offset = fObjectIdentifier (tvb, tree, offset);
+ return fAddress (tvb, tree, offset);
+}
+
+static guint
+fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+ switch (tag_no) {
+
+ case 0: /* deviceIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* objectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 2: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb,subtree,offset,&tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 3: /* propertyArrayIndex */
+ offset = fUnsignedTag (tvb,subtree,offset,"Property Array Index: ");
+ break;
+ case 4: /* propertyValue */
+ if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ case 5: /* priority */
+ offset = fUnsignedTag (tvb,subtree,offset,"Priority: ");
+ break;
+ case 6: /* quitOnFailure */
+ offset = fApplicationTypes (tvb,subtree,offset,"Quit On Failure: ",NULL);
+ break;
+ case 7: /* writeSuccessful */
+ offset = fApplicationTypes (tvb,subtree,offset,"Write Successful: ",NULL);
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ return fActionCommand (tvb,tree,offset);
+}
+
+static guint
+fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset, proto_item **tt)
+{
+ guint8 tag_no, class_tag, tmp, i;
+ guint32 lvt;
+ guint offs;
+ propertyIdentifier = 0; /* global Variable */
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ for (i = 0; i < min(lvt,4); i++) {
+ tmp = tvb_get_guint8(tvb, offset+offs+i);
+ propertyIdentifier = (propertyIdentifier << 8) + tmp;
+ }
+ *tt = proto_tree_add_text(tree, tvb, offset, min(lvt,4)+offs,
+ "property Identifier: %s", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "(%d) reserved for ASHREA"));
+ return offset+offs+min(lvt,4);
+}
+
+static guint
+fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+ guint8 tag_no, class_tag, tmp;
+ guint32 lvt, outbytesleft = 512, inbytesleft, l;
+ guint offs;
+ guint8 *str_val;
+ guint8 bf_arr[512], *out = &bf_arr[0];
+
+ if (offset < tvb_reported_length(tvb)) {
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ tmp = tvb_get_guint8(tvb, offset+offs);
+ if (tmp == 3) {
+ proto_tree_add_text (tree, tvb, offset, 4+offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
+ offset+=4+offs;
+ lvt-=4;
+ }
+ if (tmp == 4) {
+ proto_tree_add_text (tree, tvb, offset, 1+offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
+ offset+=1+offs;
+ lvt-=1;
+ }
+ if ((tmp != 3) && (tmp != 4)) {
+ proto_tree_add_text (tree, tvb, offset, offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
+ offset+=1+offs;
+ lvt--;
+ }
+ do {
+ l = inbytesleft = min(lvt, 255);
+ str_val = tvb_get_string(tvb, offset, l);
+ /** this decoding may be not correct for multi-byte characters, Lka */
+ switch (tmp) {
+ case 0x00: /* ANSI_X3.4 */
+ fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ANSI_X3.4");
+ break;
+ case 1: /* IBM/MICROSOFT DBCS */
+ out = str_val;
+ break;
+ case 2: /* JIS C 6226 */
+ out = str_val;
+ break;
+ case 3: /* UCS-4 */
+ fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-4BE");
+ break;
+ case 4: /* UCS-2 */
+ fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-2BE");
+ break;
+ case 5: /* ISO8859-1 */
+ fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ISO8859-1");
+ break;
+ default:
+ out = str_val;
+ break;
+ }
+ proto_tree_add_text(tree, tvb, offset, l, "%s'%s'", LABEL(label), out);
+ g_free(str_val);
+ lvt-=l;
+ offset+=l;
+ } while (lvt > 0);
+ }
+ return offset;
+}
+
+static guint
+fApplicationTypes (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, const value_string *src)
+{
+ guint8 tag_no, class_tag, tmp, i, j, unused;
+ guint64 val = 0;
+ guint32 lvt;
+ guint offs;
+ gfloat f_val = 0.0;
+ gdouble d_val = 0.0;
+ guint8 bf_arr[256];
+
+ if (offset < tvb_reported_length(tvb)) {
+
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ switch (tag_no) {
+ case 0: /** NULL 20.2.2 */
+ proto_tree_add_text(tree, tvb, offset++, 1, "%sNULL", LABEL(label));
+ break;
+ case 1: /** BOOLEAN 20.2.3 */
+ proto_tree_add_text(tree, tvb, offset++, 1, "%s%s", LABEL(label), lvt == 0 ? "FALSE" : "TRUE");
+ break;
+ case 2: /** Unsigned Integer 20.2.4 */
+ offset = fUnsignedTag (tvb, tree, offset, label);
+ break;
+ case 3: /** Signed Integer 20.2.5 */
+ offset = fSignedTag (tvb, tree, offset, label);
+ break;
+ case 4: /** Real 20.2.6 */
+ f_val = tvb_get_ntohieee_float(tvb, offset+offs);
+ proto_tree_add_text(tree, tvb, offset, 4+offs, "%s%f (Real)", LABEL(label), f_val);
+ offset +=4+offs;
+ break;
+ case 5: /** Double 20.2.7 */
+ d_val = tvb_get_ntohieee_double(tvb, offset+offs);
+ proto_tree_add_text(tree, tvb, offset, 8+offs, "%s%lf (Double)", LABEL(label), d_val);
+ offset+=8+offs;
+ break;
+ case 6: /** Octet String 20.2.8 */
+ proto_tree_add_text(tree, tvb, offset, 1, "%s (%d Characters)", LABEL(label), lvt);
+ offset = fOctetString (tvb, tree, offset+offs, label, lvt);
+ break;
+ case 7: /** Character String 20.2.9 */
+ offset = fCharacterString (tvb,tree,offset,label);
+ break;
+ case 8: /** Bit String 20.2.10 */
+ offset+=offs;
+ unused = tvb_get_guint8(tvb, offset); /* get the unused Bits */
+ for (i = 0; i < (lvt-2); i++) {
+ tmp = tvb_get_guint8(tvb, (offset)+i+1);
+ for (j = 0; j < 8; j++) {
+ if (src != NULL) {
+ if (tmp & (1 << (7 - j)))
+ proto_tree_add_text(tree, tvb, offset+i+1, 1, "%s%s = TRUE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
+ else
+ proto_tree_add_text(tree, tvb, offset+i+1, 1, "%s%s = FALSE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
+
+ } else {
+ bf_arr[min(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
+ }
+ }
+ }
+ tmp = tvb_get_guint8(tvb, offset+lvt-1); /* now the last Byte */
+ if (src == NULL) {
+ for (j = 0; j < (8 - unused); j++)
+ bf_arr[min(255,((lvt-2)*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
+ for (; j < 8; j++)
+ bf_arr[min(255,((lvt-2)*8)+j)] = 'x';
+ bf_arr[min(255,((lvt-2)*8)+j)] = '\0';
+ proto_tree_add_text(tree, tvb, offset, lvt, "%sB'%s'", LABEL(label), bf_arr);
+ } else {
+ for (j = 0; j < (8 - unused); j++) {
+ if (tmp & (1 << (7 - j)))
+ proto_tree_add_text(tree, tvb, offset+i+1, 1, "%s%s = TRUE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
+ else
+ proto_tree_add_text(tree, tvb, offset+i+1, 1, "%s%s = FALSE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
+ }
+ }
+ offset+=lvt;
+ break;
+ case 9: /** Enumerated 20.2.11 */
+ for (i = 0; i < min(lvt,8); i++) {
+ tmp = tvb_get_guint8(tvb, offset+offs+i);
+ val = (val << 8) + tmp;
+ }
+ if (src != NULL)
+ proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%s (%d)", LABEL(label), val_to_str((guint) val, src, "Reserved by ASHRAE"), (guint) val);
+ else
+ proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%" PRIu64, LABEL(label), val);
+
+ offset+=lvt+offs;
+ break;
+ case 10: /** Date 20.2.12 */
+ offset = fDate (tvb, tree, offset, label);
+ break;
+ case 11: /** Time 20.2.13 */
+ offset = fTime (tvb, tree, offset, label);
+ break;
+ case 12: /** BACnetObjectIdentifier 20.2.14 */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 13: /* reserved for ASHRAE */
+ case 14:
+ case 15:
+ proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s'reserved for ASHRAE'", LABEL(label));
+ offset+=lvt+offs;
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint offs, lastoffset = 0;
+ char ar[256];
+ sprintf (ar, "%s: ", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "identifier (%d) not found"));
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing tag, but not for me */
+ return offset;
+ }
+ /* Application Tags */
+ switch (propertyIdentifier) {
+ case 2: /* BACnetActionList */
+ offset = fActionList (tvb,tree,offset);
+ break;
+ case 30: /* BACnetAddressBinding */
+ offset = fAddressBinding (tvb,tree,offset);
+ break;
+ case 38: /* exception-schedule */
+ offset = fSpecialEvent (tvb,tree,offset);
+ break;
+ case 97: /* Protocol-Services-Supported */
+ offset = fApplicationTypes (tvb, tree, offset, ar, BACnetServicesSupported);
+ break;
+ case 111: /* Status-Flags */
+ case 112: /* System-Status */
+ offset = fApplicationTypes (tvb, tree, offset, ar, BACnetStatusFlags);
+ break;
+ case 117: /* units */
+ offset = fApplicationTypes (tvb, tree, offset, ar, BACnetUnits);
+ break;
+ case 76: /* object-list */
+ offset = fApplicationTypes (tvb, tree, offset, ar, NULL);
+ break;
+ case 87: /* priority-array */
+ offset = fPriorityArray (tvb, tree, offset);
+ break;
+ case 123: /* weekly-schedule */
+ offset = fWeeklySchedule (tvb,tree,offset);
+ break;
+ default:
+ offset = fApplicationTypes (tvb, tree, offset, ar, NULL);
+ break;
+ }
+ }
+ return offset;
+
+}
+
+static guint
+fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ gboolean awaitingClosingTag = false;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (class_tag) {
+ if ((lvt == 7) && !awaitingClosingTag) { /* closing Tag */
+ return offset; /* but not for me */
+ }
+ if (lvt == 7) { /* closing Tag for me */
+ subtree = tree;
+ offset++;
+ awaitingClosingTag = false;
+ continue;
+ }
+ switch (tag_no) {
+ case 0: /* PropertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 1: /* propertyArrayIndex */
+ offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ case 2: /* Value */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ awaitingClosingTag = true;
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ case 3: /* Priority */
+ offset = fSignedTag (tvb, subtree, offset, "Priority: ");
+ break;
+ default:
+ return offset;
+ break;
+ }
+ } else {
+ offset = fAbstractSyntaxNType (tvb,tree,offset);
+ }
+ }
+ return offset;
+}
+
+static guint
+fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* ProcessId */
+ offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
+ break;
+ case 1: /* monitored ObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 2: /* issueConfirmedNotifications */
+ offset = fApplicationTypes (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
+ break;
+ case 3: /* life time */
+ offset = fTimeSpan (tvb,tree,offset,"life time");
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fCOVSubscription(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* Recipient */
+ offset = fRecipientProcess (tvb, tree, offset);
+ break;
+ case 1: /* monitoredPropertyReference */
+ offset = fPropertyReference (tvb, tree, offset);
+ break;
+ case 2: /* issueConfirmedNotifications */
+ offset = fApplicationTypes (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
+ break;
+ case 3: /* time remaining */
+ offset = fTimeSpan (tvb,tree,offset,"time remaining");
+ break;
+ case 4: /* COVIncrement */
+ offset = fApplicationTypes(tvb,tree,offset,"COV Increment: ", NULL);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* deviceInstanceLowLimit */
+ offset = fUnsignedTag (tvb, tree, offset, "device Instance Low Limit: ");
+ break;
+ case 1: /* deviceInstanceHighLimit */
+ offset = fUnsignedTag (tvb, tree, offset, "device Instance High Limit: ");
+ break;
+ case 2: /* BACnetObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 3: /* messageText */
+ offset = fCharacterString (tvb,tree,offset, "Object Name: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+
+static guint
+fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ offset++;
+ return offset;
+ }
+
+ switch (tag_no) {
+ case 0: /* day-schedule */
+ if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
+ offset = fTimeValue (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint i=1;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ offset++;
+ return offset;
+ }
+ tt = proto_tree_add_text(tree, tvb, offset, 0, val_to_str(i++, days, "day of week (%d) not found"));
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fDailySchedule (tvb,subtree,offset);
+
+ }
+ return offset;
+}
+
+
+static guint
+fUTCTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+
+ return fDateTime (tvb, tree, offset, "UTC-Time: ");
+}
+
+static guint
+fTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+
+ return fDateTime (tvb, tree, offset, NULL);
+}
+
+static guint
+fDateRange (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+ offset = fDate (tvb,tree,offset,"Start Date: ");
+ return fDate (tvb, tree, offset, "End Date: ");
+}
+
+static guint
+fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* textMessageSourceDevice */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 1: /* messageClass */
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* numeric */
+ offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
+ break;
+ case 1: /* character */
+ offset = fApplicationTypes (tvb, tree, offset, "message Class: ", NULL);
+ break;
+ }
+ break;
+ case 2: /* messagePriority */
+ offset = fApplicationTypes (tvb, tree, offset, "Object Name: ", BACnetMessagePriority);
+ break;
+ case 3: /* message */
+ offset = fApplicationTypes (tvb, tree, offset, "message: ", NULL);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* textMessageSourceDevice */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 1: /* messageClass */
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* numeric */
+ offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
+ break;
+ case 1: /* character */
+ offset = fApplicationTypes (tvb, tree, offset, "message Class: ", NULL);
+ break;
+ }
+ break;
+ case 2: /* messagePriority */
+ offset = fApplicationTypes (tvb, tree, offset, "Object Name: ", BACnetMessagePriority);
+ break;
+ case 3: /* message */
+ offset = fApplicationTypes (tvb, tree, offset, "message: ", NULL);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+ switch (tag_no) {
+
+ case 0: /* vendorID */
+ offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
+ break;
+ case 1: /* serviceNumber */
+ offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
+ break;
+ case 2: /*serviceParameters */
+ if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
+ tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+
+static guint
+fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+ switch (tag_no) {
+
+ case 0: /* vendorID */
+ offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
+ break;
+ case 1: /* serviceNumber */
+ offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
+ break;
+ case 2: /*serviceParameters */
+ if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
+ tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+ switch (tag_no) {
+
+ case 0: /* vendorID */
+ offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
+ break;
+ case 1: /* serviceNumber */
+ offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
+ break;
+ case 2: /*serviceParameters */
+ if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
+ tt = proto_tree_add_text(subtree, tvb, offset, 1, "result Block");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ if (label != NULL) {
+ tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", LABEL(label));
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ }
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ switch (tag_no) {
+ case 0: /* subscriberProcessId */
+ offset = fUnsignedTag (tvb, subtree, offset, "requesting Process Id: ");
+ break;
+ case 1: /* requestingSource */
+ offset = fApplicationTypes (tvb, subtree, offset, "requesting Source: ", NULL);
+ break;
+ case 2: /* request */
+ offset = fApplicationTypes (tvb, subtree, offset, "request: ", BACnetLifeSafetyOperation);
+ break;
+ case 3: /* objectId */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* change-of-bitstring */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fApplicationTypes (tvb, tree, offset, "referenced-bitstring: ", NULL);
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ break;
+ case 1: /* change-of-state */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fApplicationTypes (tvb, tree, offset, "new-state: ", BACnetPropertyStates);
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ break;
+ case 2: /* change-of-value */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: offset++;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fApplicationTypes (tvb, tree, offset, "changed-bits: ", NULL);
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "changed-value: ", NULL);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+ default:
+ return offset;
+ break;
+ }
+ }
+ break;
+ case 3: /* command-failure */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* "command-value: " */
+ offset = fAbstractSyntaxNType (tvb, tree, offset);
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+ case 2: /* "feedback-value: " */
+ offset = fAbstractSyntaxNType (tvb, tree, offset);
+ default:
+ return offset;
+ break;
+ }
+ }
break;
- case 0x10:
- max_segs = 2;
+ case 4: /* floating-limit */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fApplicationTypes (tvb, tree, offset, "reference-value: ", NULL);
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "setpoint-value: ", NULL);
+ break;
+ case 3:
+ offset = fApplicationTypes (tvb, tree, offset, "error-limit: ", NULL);
+ default:
+ return offset;
+ break;
+ }
+ }
+ break;
+ case 5: /* out-of-range */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fApplicationTypes (tvb, tree, offset, "exceeding-value: ", NULL);
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "deadband: ", NULL);
+ break;
+ case 3:
+ offset = fApplicationTypes (tvb, tree, offset, "exceeded-limit: ", NULL);
+ default:
+ return offset;
+ break;
+ }
+ }
break;
- case 0x20:
- max_segs = 4;
+ case 6:
+ offset = fPropertyValue (tvb,tree,offset);
+ break;
+ case 7: /* buffer-ready */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fObjectIdentifier (tvb, tree, offset); /* buffer-device */
+ break;
+ case 1:
+ offset = fObjectIdentifier (tvb, tree, offset); /* buffer-object */
+ break;
+ case 2:
+ offset = fDateTime (tvb, tree, offset, "previous-notification: ");
+ break;
+ case 3:
+ offset = fDateTime (tvb, tree, offset, "current-notification: ");
+ default:
+ return offset;
+ break;
+ }
+ }
break;
- case 0x30:
- max_segs = 8;
+ case 8: /* change-of-life-safety */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fApplicationTypes (tvb, tree, offset, "new-state: ", BACnetLifeSafetyState);
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "new-mode: ", BACnetLifeSafetyState);
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
+ case 3:
+ offset = fLifeSafetyOperationRequest(tvb, tree, offset, "operation-expected: ");
+ default:
+ return offset;
+ break;
+ }
+ }
break;
- case 0x40:
- max_segs = 16;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fEventParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* change-of-bitstring */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fTimeSpan (tvb, tree, offset, "Time Delay");
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "bitmask: ", NULL);
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "bitstring value: ", BACnetEventTransitionBits);
+ break;
+ default:
+ return offset;
+ }
+ }
break;
- case 0x50:
- max_segs = 32;
+ case 1: /* change-of-state */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fTimeSpan (tvb, tree, offset, "Time Delay");
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "value: ", BACnetStatusFlags);
+ break;
+ default:
+ return offset;
+ }
+ }
+ break;
+ case 2: /* change-of-value */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fTimeSpan (tvb, tree, offset, "Time Delay");
+ break;
+ case 1: /* don't loop it, it's a CHOICE */
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fApplicationTypes (tvb, tree, offset, "bitmask: ", NULL);
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "referenced Property Incremental: ", NULL);
+ break;
+ default:
+ return offset;
+ }
+ default:
+ return offset;
+ }
+ }
+ break;
+ case 3: /* command-failure */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fTimeSpan (tvb, tree, offset, "Time Delay");
+ break;
+ case 1:
+ offset = fDeviceObjectPropertyReference (tvb,tree,offset);
+ default:
+ return offset;
+ }
+ }
break;
- case 0x60:
- max_segs = 64;
+ case 4: /* floating-limit */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fTimeSpan (tvb, tree, offset, "Time Delay");
+ break;
+ case 1:
+ offset = fDeviceObjectPropertyReference (tvb,tree,offset);
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "low diff limit: ", NULL);
+ break;
+ case 3:
+ offset = fApplicationTypes (tvb, tree, offset, "high diff limit: ", NULL);
+ break;
+ case 4:
+ offset = fApplicationTypes (tvb, tree, offset, "deadband: ", NULL);
+ break;
+ default:
+ return offset;
+ }
+ }
+ break;
+ case 5: /* out-of-range */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fTimeSpan (tvb, tree, offset, "Time Delay");
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "low limit: ", NULL);
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "high limit: ", NULL);
+ break;
+ case 3:
+ offset = fApplicationTypes (tvb, tree, offset, "deadband: ", NULL);
+ break;
+ default:
+ return offset;
+ }
+ }
break;
- case 0x70:
- max_segs = 65;
+ case 6:
+ offset = fPropertyValue (tvb,tree,offset);
+ break;
+ case 7: /* buffer-ready */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fUnsignedTag (tvb,tree,offset,"notification threshold");
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "previous notification count: ", NULL);
+ break;
+ default:
+ return offset;
+ }
+ }
break;
- default:
+ case 8: /* change-of-life-safety */
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0:
+ offset = fTimeSpan (tvb, tree, offset, "Time Delay");
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "life safety alarm value: ", BACnetLifeSafetyState);
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "alarm value: ", BACnetLifeSafetyState);
+ break;
+ case 3:
+ offset = fDeviceObjectPropertyReference (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ }
+ }
break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* timestamp */
+ offset = fDateTime (tvb,tree,offset,NULL);
+ break;
+ case 1: /* logDatum: don't loop, it's a CHOICE */
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* logStatus */
+ offset = fApplicationTypes (tvb, tree, offset, "log status: ", BACnetLogStatus);
+ break;
+ case 1:
+ offset = fApplicationTypes (tvb, tree, offset, "boolean-value: ", NULL);
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "real value: ", NULL);
+ break;
+ case 3:
+ offset = fApplicationTypes (tvb, tree, offset, "enum value: ", NULL);
+ break;
+ case 4:
+ offset = fUnsignedTag (tvb, tree, offset, "unsigned value: ");
+ break;
+ case 5:
+ offset = fApplicationTypes (tvb, tree, offset, "signed value: ", NULL);
+ break;
+ case 6:
+ offset = fApplicationTypes (tvb, tree, offset, "bitstring value: ", NULL);
+ break;
+ case 7:
+ offset = fApplicationTypes (tvb, tree, offset, "null value: ", NULL);
+ break;
+ case 8:
+ offset = fError (tvb,tree,offset);
+ break;
+ case 9:
+ offset = fApplicationTypes (tvb, tree, offset, "time change: ", NULL);
+ break;
+ case 10: /* any Value */
+ offset = fAbstractSyntaxNType (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ }
+ break;
+ case 2:
+ offset = fApplicationTypes (tvb, tree, offset, "status Flags: ", BACnetStatusFlags);
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* ProcessId */
+ offset = fProcessId (tvb,tree,offset);
+ break;
+ case 1: /* initiating ObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 2: /* event ObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 3: /* time stamp */
+ offset = fApplicationTypes (tvb, tree, offset, "Time Stamp: ", NULL);
+ break;
+ case 4: /* notificationClass */
+ offset = fApplicationTypes (tvb, tree, offset, "Notification Class: ", NULL);
+ break;
+ case 5: /* Priority */
+ offset = fApplicationTypes (tvb, tree, offset, "Priority: ", NULL);
+ break;
+ case 6: /* EventType */
+ offset = fApplicationTypes (tvb, tree, offset, "Event Type: ", BACnetEventType);
+ break;
+ case 7: /* messageText */
+ offset = fApplicationTypes (tvb, tree, offset, "message Text: ", NULL);
+ break;
+ case 8: /* NotifyType */
+ offset = fApplicationTypes (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
+ break;
+ case 9: /* ackRequired */
+ offset = fApplicationTypes (tvb, tree, offset, "ack Required: ", NULL);
+ break;
+ case 10: /* fromState */
+ offset = fApplicationTypes (tvb, tree, offset, "from State: ", BACnetEventState);
+ break;
+ case 11: /* toState */
+ offset = fApplicationTypes (tvb, tree, offset, "to State: ", BACnetEventState);
+ break;
+ case 12: /* NotificationParameters */
+ offset = fNotificationParameters (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* ProcessId */
+ offset = fProcessId (tvb,tree,offset);
+ break;
+ case 1: /* initiating ObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 2: /* event ObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 3: /* time stamp */
+ offset = fApplicationTypes (tvb, tree, offset, "Time Stamp: ", NULL);
+ break;
+ case 4: /* notificationClass */
+ offset = fApplicationTypes (tvb, tree, offset, "Notification Class: ", NULL);
+ break;
+ case 5: /* Priority */
+ offset = fApplicationTypes (tvb, tree, offset, "Priority: ", NULL);
+ break;
+ case 6: /* EventType */
+ offset = fApplicationTypes (tvb, tree, offset, "Event Type: ", BACnetEventType);
+ break;
+ case 7: /* messageText */
+ offset = fApplicationTypes (tvb, tree, offset, "message Text: ", NULL);
+ break;
+ case 8: /* NotifyType */
+ offset = fApplicationTypes (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
+ break;
+ case 9: /* ackRequired */
+ offset = fApplicationTypes (tvb, tree, offset, "ack Required: ", NULL);
+ break;
+ case 10: /* fromState */
+ offset = fApplicationTypes (tvb, tree, offset, "from State: ", BACnetEventState);
+ break;
+ case 11: /* toState */
+ offset = fApplicationTypes (tvb, tree, offset, "to State: ", BACnetEventState);
+ break;
+ case 12: /* NotificationParameters */
+ offset = fNotificationParameters (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* ProcessId */
+ offset = fProcessId (tvb,tree,offset);
+ break;
+ case 1: /* initiating ObjectId */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 2: /* monitored ObjectId */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 3: /* time remaining */
+ offset = fTimeSpan (tvb, tree, offset, "Time remaining");
+ break;
+ case 4: /* List of Values */
+ if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
+ tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fPropertyValue (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* subscriberProcessId */
+ offset = fProcessId (tvb,tree,offset);
+ break;
+ case 1: /* initiating ObjectId */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 2: /* monitored ObjectId */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 3: /* time remaining */
+ offset = fTimeSpan (tvb, tree, offset, "Time remaining");
+ break;
+ case 4: /* List of Values */
+ if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
+ tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fPropertyValue (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAcknowlegdeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* acknowledgingProcessId */
+ offset = fUnsignedTag (tvb, tree, offset, "acknowledging Process Id: ");
+ break;
+ case 1: /* eventObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 2: /* eventStateAcknowledged */
+ fApplicationTypes (tvb, tree, offset, "event State Acknowledged: ", BACnetEventState);
+ break;
+ case 3: /* timeStamp */
+ offset = fTime (tvb, tree, offset, "time Stamp: ");
+ break;
+ case 4: /* acknowledgementSource */
+ offset = fApplicationTypes (tvb, tree, offset, "acknowledgement Source: ", NULL);
+ break;
+ case 5: /* timeOfAcknowledgement */
+ offset = fTime (tvb, tree, offset, "time Of Acknowledgement: ");
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fGetAlarmSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ offset = fObjectIdentifier (tvb, tree, offset);
+ offset = fApplicationTypes (tvb, tree, offset, "alarm State: ", BACnetEventState);
+ offset = fApplicationTypes (tvb, tree, offset, "acknowledged Transitions: ", BACnetEventTransitionBits);
+ }
+ return offset;
+}
+
+static guint
+fGetEnrollmentSummaryRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* acknowledgmentFilter */
+ offset = fApplicationTypes (tvb, tree, offset, "acknowledgment Filter: ", BACnetAcknowledgementFilter);
+ break;
+ case 1: /* eventObjectId */
+ offset = fRecipientProcess (tvb, tree, offset);
+ break;
+ case 2: /* eventStateFilter */
+ offset = fApplicationTypes (tvb, tree, offset, "event State Filter: ", BACnetEventStateFilter);
+ break;
+ case 3: /* eventTypeFilter */
+ offset = fApplicationTypes (tvb, tree, offset, "event Type Filter: ", BACnetEventType);
+ break;
+ case 4: /* priorityFilter */
+ offset = fUnsignedTag (tvb, tree, offset, "min Priority: ");
+ offset = fUnsignedTag (tvb, tree, offset, "max Priority: ");
+ break;
+ case 5: /* notificationClassFilter */
+ offset = fUnsignedTag (tvb, tree, offset, "notification Class Filter: ");
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fGetEnrollmentSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ offset = fObjectIdentifier (tvb, tree, offset);
+ offset = fApplicationTypes (tvb, tree, offset, "event Type: ", BACnetEventType);
+ offset = fApplicationTypes (tvb, tree, offset, "event State: ", BACnetEventStateFilter);
+ offset = fUnsignedTag (tvb, tree, offset, "Priority: ");
+ offset = fUnsignedTag (tvb, tree, offset, "notification Class: ");
+ }
+
+ return offset;
+}
+
+static guint
+fGetEventInformationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* lastReceivedObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+flistOfEventSummaries (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* ObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 1: /* eventState */
+ offset = fApplicationTypes (tvb, tree, offset, "event State: ", BACnetEventStateFilter);
+ break;
+ case 2: /* acknowledgedTransitions */
+ offset = fApplicationTypes (tvb, tree, offset, "acknowledged Transitions: ", BACnetEventTransitionBits);
+ break;
+ case 3: /* eventTimeStamps */
+ offset = fTime (tvb, tree, offset, "time Stamp: ");
+ offset = fTime (tvb, tree, offset, "time Stamp: ");
+ offset = fTime (tvb, tree, offset, "time Stamp: ");
+ break;
+ case 4: /* notifyType */
+ offset = fApplicationTypes (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
+ break;
+ case 5: /* eventEnable */
+ offset = fApplicationTypes (tvb, tree, offset, "event Enable: ", BACnetEventTransitionBits);
+ break;
+ case 6: /* eventPriorities */
+ offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
+ offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
+ offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fGetEventInformationACK (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* listOfEventSummaries */
+ offset = flistOfEventSummaries (tvb, tree, offset);
+ break;
+ case 1: /* moreEvents */
+ offset = fApplicationTypes (tvb, tree, offset, "more Events: ", NULL);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAddListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* ObjectId */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 2: /* propertyArrayIndex */
+ offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ case 3: /* listOfElements */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fDeleteObjectRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ return fObjectIdentifier (tvb, tree, offset);
+}
+
+static guint
+fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* timeDuration */
+ offset = fUnsignedTag (tvb,tree,offset,"time Duration: ");
+ break;
+ case 1: /* enable-disable */
+ offset = fApplicationTypes (tvb, tree, offset, "enable-disable: ", BACnetEnableDisable);
+ break;
+ case 2: /* password */
+ offset = fApplicationTypes (tvb, tree, offset, "Password: ", NULL);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* reinitializedStateOfDevice */
+ offset = fApplicationTypes (tvb, tree, offset, "reinitialized State Of Device: ", BACnetReinitializedStateOfDevice);
+ break;
+ case 1: /* password */
+ offset = fApplicationTypes (tvb, tree, offset, "Password: ", NULL);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fVtOpenRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+ offset = fApplicationTypes (tvb, tree, offset, "vtClass: ", BACnetVTClass);
+ return fUnsignedTag (tvb,tree,offset,"local VT Session ID: ");
+}
+
+static guint
+fVtOpenAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+ return offset= fUnsignedTag (tvb,tree,offset,"remote VT Session ID: ");
+}
+
+static guint
+fVtCloseRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ offset= fUnsignedTag (tvb,tree,offset,"remote VT Session ID: ");
+ }
+ return offset;
+}
+
+static guint
+fVtDataRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+ offset= fUnsignedTag (tvb,tree,offset,"VT Session ID: ");
+ offset = fApplicationTypes (tvb, tree, offset, "VT New Data: ", NULL);
+ return fUnsignedTag (tvb,tree,offset,"VT Data Flag: ");;
+}
+
+static guint
+fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* BOOLEAN */
+ offset = fApplicationTypes (tvb, tree, offset, "all New Data Accepted: ", NULL);
+ break;
+ case 1: /* Unsigned OPTIONAL */
+ offset = fUnsignedTag (tvb, tree, offset, "accepted Octet Count: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* Unsigned32 */
+ offset = fUnsignedTag (tvb, tree, offset, "pseudo Random Number: ");
+ break;
+ case 1: /* expected Invoke ID Unsigned8 OPTIONAL */
+ proto_tree_add_item(tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
+ break;
+ case 2: /* Chararacter String OPTIONAL */
+ offset = fApplicationTypes (tvb, tree, offset, "operator Name: ", NULL);
+ break;
+ case 3: /* Chararacter String OPTIONAL */
+ offset = fApplicationTypes (tvb, tree, offset, "operator Password: ", NULL);
+ break;
+ case 4: /* Boolean OPTIONAL */
+ offset = fApplicationTypes (tvb, tree, offset, "start Encyphered Session: ", NULL);
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAuthenticateAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ return fUnsignedTag (tvb, tree, offset, "modified Random Number: ");
+}
+
+static guint
+fRequestKeyRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+
+ offset = fObjectIdentifier (tvb, tree, offset); /* Requesting Device Identifier */
+ offset = fAddress (tvb, tree, offset);
+ offset = fObjectIdentifier (tvb, tree, offset); /* Remote Device Identifier */
+ return fAddress (tvb, tree, offset);
+}
+
+static guint
+fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* subscriberProcessId */
+ offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
+ break;
+ case 1: /* monitored ObjectId */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 2: /* issueConfirmedNotifications */
+ offset = fApplicationTypes (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
+ break;
+ case 3: /* life time */
+ offset = fTimeSpan (tvb,tree,offset,"life time");
+ break;
+ case 4: /* monitoredPropertyIdentifier */
+ offset = fApplicationTypes (tvb, tree, offset, "monitored Property Id: ", NULL);
+ break;
+ case 5: /* covIncrement */
+ offset = fUnsignedTag (tvb, tree, offset, "cov Increment: ");
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fRemoveListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* ObjectId */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 2: /* propertyArrayIndex */
+ offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ case 3: /* listOfElements */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fReadPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* objectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ break;
+ case 2: /* propertyArrayIndex */
+ offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fReadPropertyAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) {
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 2: /* propertyArrayIndex */
+ offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ case 3: /* propertyValue */
+ if ((lvt == 6) && class_tag) { offset++;
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ /* offset = fPropertyValue (tvb,subtree,offset); */
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fWritePropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) {
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ break;
+ case 2: /* propertyArrayIndex */
+ offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ case 3: /* propertyValue */
+ if ((lvt == 6) && class_tag) { offset++;
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ case 4: /* Priority (only used for write) */
+ offset = fSignedTag (tvb, subtree, offset, "Priority: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* listOfPropertyValues */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fPropertyValue (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fWritePropertyMultipleRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+
+ return fWriteAccessSpecification (tvb, tree, offset);
+}
+
+static guint
+fPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree* subtree = tree;
+ proto_item* tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag, but not for me */
+ return offset;
+ }
+ switch (tag_no) {
+ case 0: /* PropertyIdentifier */
+ offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 1: /* propertyArrayIndex */
+ offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ proto_tree* subtree = tree;
+ proto_item* tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* ObjectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* PropertyIdentifier */
+ offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 2: /* propertyArrayIndex */
+ offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree* subtree = tree;
+ proto_item* tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++; /* check it again, Lka */
+ continue;
+ }
+ switch (tag_no) {
+ case 0: /* ObjectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* PropertyIdentifier */
+ offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 2: /* propertyArrayIndex */
+ offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ case 3: /* Value */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ case 4: /* Priority */
+ offset = fSignedTag (tvb, subtree, offset, "Priority: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+
+static guint
+fDeviceObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ proto_tree* subtree = tree;
+ proto_item* tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* ObjectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* PropertyIdentifier */
+ offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 2: /* propertyArrayIndex */
+ offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ case 3: /* deviceIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fPriorityArray (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint8 i, ar[256];
+
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+
+ for (i = 1; i <= 16; i++) {
+
+ sprintf (ar, "%s[%d]: ", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "identifier (%d) not found"), i);
+ offset = fApplicationTypes (tvb, tree, offset, ar, BACnetBinaryPV);
+ }
+ return offset;
+}
+
+static guint
+fDeviceObjectReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* deviceIdentifier */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ case 1: /* ObjectIdentifier */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fSpecialEvent (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ continue;
+ }
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* calendaryEntry */
+ offset = fCalendaryEntry (tvb, subtree, offset);
+ break;
+ case 1: /* calendarReference */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 2: /* calendarReference */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fTimeValue (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ case 3: /* eventPriority */
+ offset = fUnsignedTag (tvb, subtree, offset, "event priority: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fSelectionCriteria (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+
+ switch (fTagNo(tvb,offset)) {
+ case 0: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, tree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 1: /* propertyArrayIndex */
+ offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
+ break;
+ case 2: /* relationSpecifier */
+ offset = fApplicationTypes (tvb, subtree, offset, "relation Specifier: ", BACnetRelationSpecifier);
+ break;
+ case 3: /* comparisonValue */
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* selectionLogic */
+ offset = fApplicationTypes (tvb, subtree, offset, "selection Logic: ", BACnetSelectionLogic);
+ break;
+ case 1: /* listOfSelectionCriteria */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fSelectionCriteria (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+
+static guint
+fReadPropertyConditionalRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectSelectionCriteria */
+ offset = fObjectSelectionCriteria (tvb, subtree, offset);
+ break;
+ case 1: /* listOfPropertyReferences */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fPropertyReference (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fReadAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectIdentifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* listOfPropertyReferences */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fPropertyReference (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no;
+ guint8 class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectSpecifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* list of Results */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ break;
+ }
+ FAULT;
+ break;
+ case 2: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_list);
+ break;
+ case 3: /* propertyArrayIndex Optional */
+ offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
+ break;
+ case 4: /* propertyValue */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ case 5: /* propertyAccessError */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ /* Error Code follows */
+ offset = fApplicationTypes (tvb, subtree, offset, "error Class: ", BACnetErrorClass);
+ offset = fApplicationTypes (tvb, subtree, offset, "error Code: ", BACnetErrorCode);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+
+static guint
+fReadPropertyConditionalAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ /* listOfReadAccessResults */
+ return fReadAccessResult (tvb, tree, offset);
+}
+
+
+static guint
+fObjectSpecifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* objectType */
+ proto_tree_add_item(tree, hf_bacapp_tag_initiatingObjectType, tvb, offset++, 1, TRUE);
+ break;
+ case 1: /* objectIdentifier */
+ offset = fObjectIdentifier (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fCreateObjectRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+
+ while ((offset < tvb_reported_length(tvb)) && (offset > lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectSpecifier */
+ offset = fObjectSpecifier (tvb, subtree, offset);
+ break;
+ case 1: /* propertyValue */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fPropertyValue (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ return fObjectIdentifier (tvb, tree, offset);
+}
+
+static guint
+fReadRangeRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectSpecifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 2: /* propertyArrayIndex Optional */
+ offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
+ break;
+ case 3: /* range byPosition */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fApplicationTypes (tvb, subtree, offset, "reference Index: ", NULL);
+ offset = fApplicationTypes (tvb, subtree, offset, "reference Count: ", NULL);
+ break;
+ }
+ FAULT;
+ break;
+ case 4: /* range byTime */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fApplicationTypes (tvb, subtree, offset, "reference Time: ", NULL);
+ offset = fApplicationTypes (tvb, subtree, offset, "reference Count: ", NULL);
+ break;
+ }
+ FAULT;
+ break;
+ case 5: /* range timeRange */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fApplicationTypes (tvb, subtree, offset, "beginning Time: ", NULL);
+ offset = fApplicationTypes (tvb, subtree, offset, "ending Time: ", NULL);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fReadRangeAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ subtree = tree;
+ offset++;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* objectSpecifier */
+ offset = fObjectIdentifier (tvb, subtree, offset);
+ break;
+ case 1: /* propertyIdentifier */
+ offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ break;
+ case 2: /* propertyArrayIndex Optional */
+ offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
+ break;
+ case 3: /* resultFlags */
+ offset = fApplicationTypes (tvb, subtree, offset, "result Flags: ", BACnetResultFlags);
+ break;
+ case 4: /* itemCount */
+ offset = fUnsignedTag (tvb, subtree, offset, "item Count: ");
+ break;
+ case 5: /* itemData */
+ if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
+ offset = fAbstractSyntaxNType (tvb, subtree, offset);
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAtomicReadFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ offset = fObjectIdentifier (tvb, tree, offset);
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ subtree = tree;
+ continue;
+ }
+
+ switch (tag_no) {
+ case 0: /* streamAccess */
+ if ((lvt == 6) && class_tag) { /* opening Tag */
+ tt = proto_tree_add_text(subtree, tvb, offset++, 1, "stream Access");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
+ offset = fUnsignedTag (tvb, subtree, offset, "requestet Octet Count: ");
+ break;
+ }
+ FAULT;
+ break;
+ case 1: /* recordAccess */
+ if ((lvt == 6) && class_tag) { /* opening Tag */
+ tt = proto_tree_add_text(subtree, tvb, offset++, 1, "record Access");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fSignedTag (tvb, subtree, offset, "File Start Record: ");
+ offset = fUnsignedTag (tvb, subtree, offset, "requestet Record Count: ");
+ break;
+ }
+ FAULT;
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) { /* Segment of an Request */
+ if (bacapp_flags & 0x04) { /* More Flag is set */
+ offset = fOctetString (tvb, tree, offset, "file Data: ", 0);
+ } else {
+ offset = fOctetString (tvb, tree, offset, "file Data: ", tvb_reported_length(tvb) - offset - 1);
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ }
+ }
+ } else {
+ offset = fObjectIdentifier (tvb, tree, offset); /* file Identifier */
+
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ switch (tag_no) {
+ case 0: /* streamAccess */
+ if ((lvt == 6) && class_tag) { /* opening Tag */
+ tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
+ offset = fApplicationTypes (tvb, subtree, offset, "file Data: ", NULL);
+ }
+ if (bacapp_flags && 0x04) { /* More Flag is set */
+ break;
+ }
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ offset++;
+ subtree = tree;
+ }
+ break;
+ case 1: /* recordAccess */
+ if ((lvt == 6) && class_tag) { /* opening Tag */
+ tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fSignedTag (tvb, subtree, offset, "file Start Record: ");
+ offset = fUnsignedTag (tvb, subtree, offset, "Record Count: ");
+ offset = fApplicationTypes (tvb, subtree, offset, "file Data: ", NULL);
+ }
+ if (bacapp_flags && 0x04) { /* More Flag is set */
+ break;
+ }
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if (((lvt == 7) && class_tag)) { /* closing Tag */
+ offset++;
+ subtree = tree;
+ }
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* streamAccess */
+ offset = fSignedTag (tvb, tree, offset, "File Start Position: ");
+ break;
+ case 1: /* recordAccess */
+ offset = fSignedTag (tvb, tree, offset, "File Start Record: ");
+ break;
+ default:
+ return offset;
+ }
+ return offset;
+}
+
+static guint
+fAtomicReadFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint8 tag_no, class_tag;
+ guint32 lvt;
+ proto_tree *subtree = tree;
+ proto_item *tt;
+
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) { /* Segment of an Request */
+ if (bacapp_flags & 0x04) { /* More Flag is set */
+ offset = fOctetString (tvb, tree, offset, "File Data: ", 0);
+ } else {
+ offset = fOctetString (tvb, tree, offset, "File Data: ", tvb_reported_length(tvb)-offset-1);
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ }
+ }
+ } else {
+ offset = fApplicationTypes (tvb, subtree, offset, "End Of File: ", NULL);
+
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+
+ switch (tag_no) {
+ case 0: /* streamAccess */
+ if ((lvt == 6) && class_tag) { /* opening Tag */
+ tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
+ subtree = proto_item_add_subtree(tt, ett_bacapp_value);
+ offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
+ offset = fApplicationTypes (tvb, subtree, offset, "file Data: ", NULL);
+ }
+ if (bacapp_flags && 0x04) { /* More Flag is set */
+ break;
+ }
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ subtree = tree;
+ }
+ break;
+ case 1: /* recordAccess */
+ if ((lvt == 6) && class_tag) { /* opening Tag */
+ proto_tree_add_text(tree, tvb, offset++, 1, "stream Access {");
+ offset = fSignedTag (tvb, subtree, offset, "File Start Record: ");
+ offset = fUnsignedTag (tvb, subtree, offset, "returned Record Count: ");
+ offset = fApplicationTypes (tvb, subtree, offset, "Data: ", NULL);
+ }
+ if (bacapp_flags && 0x04) { /* More Flag is set */
+ break;
+ }
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ if ((lvt == 7) && class_tag) { /* closing Tag */
+ offset++;
+ subtree = tree;
+ }
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fReadPropertyMultipleRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
+{
+ return fReadAccessSpecification (tvb,subtree,offset);
+}
+
+static guint
+fReadPropertyMultipleAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ return fReadAccessResult (tvb,tree,offset);
+}
+
+static guint
+fConfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+
+ switch (service_choice) {
+ case 0: /* acknowledgeAlarm */
+ offset = fAcknowlegdeAlarmRequest (tvb, tree, offset);
+ break;
+ case 1: /* confirmedCOVNotification */
+ offset = fConfirmedCOVNotificationRequest (tvb, tree, offset);
+ break;
+ case 2: /* confirmedEventNotification */
+ offset = fConfirmedEventNotificationRequest (tvb, tree, offset);
+ break;
+ case 3: /* confirmedGetAlarmSummary conveys no parameters */
+ break;
+ case 4: /* getEnrollmentSummaryRequest */
+ offset = fGetEnrollmentSummaryRequest (tvb, tree, offset);
+ break;
+ case 5: /* subscribeCOVRequest */
+ offset = fSubscribeCOVRequest(tvb, tree, offset);
+ break;
+ case 6: /* atomicReadFile-Request */
+ offset = fAtomicReadFileRequest(tvb, tree, offset);
+ break;
+ case 7: /* atomicWriteFile-Request */
+ offset = fAtomicWriteFileRequest(tvb, tree, offset);
+ break;
+ case 8: /* AddListElement-Request */
+ offset = fAddListElementRequest(tvb, tree, offset);
+ break;
+ case 9: /* removeListElement-Request */
+ offset = fRemoveListElementRequest(tvb, tree, offset);
+ break;
+ case 10: /* createObjectRequest */
+ offset = fCreateObjectRequest(tvb, tree, offset);
+ break;
+ case 11: /* deleteObject */
+ offset = fDeleteObjectRequest(tvb, tree, offset);
+ break;
+ case 12:
+ offset = fReadPropertyRequest(tvb, tree, offset);
+ break;
+ case 13:
+ offset = fReadPropertyConditionalRequest(tvb, tree, offset);
+ break;
+ case 14:
+ offset = fReadPropertyMultipleRequest(tvb, tree, offset);
+ break;
+ case 15:
+ offset = fWritePropertyRequest(tvb, tree, offset);
+ break;
+ case 16:
+ offset = fWritePropertyMultipleRequest(tvb, tree, offset);
+ break;
+ case 17:
+ offset = fDeviceCommunicationControlRequest(tvb, tree, offset);
+ break;
+ case 18:
+ offset = fConfirmedPrivateTransferRequest(tvb, tree, offset);
+ break;
+ case 19:
+ offset = fConfirmedTextMessageRequest(tvb, tree, offset);
+ break;
+ case 20:
+ offset = fReinitializeDeviceRequest(tvb, tree, offset);
+ break;
+ case 21:
+ offset = fVtOpenRequest(tvb, tree, offset);
+ break;
+ case 22:
+ offset = fVtCloseRequest (tvb, tree, offset);
+ break;
+ case 23:
+ offset = fVtDataRequest (tvb, tree, offset);
+ break;
+ case 24:
+ offset = fAuthenticateRequest (tvb, tree, offset);
+ break;
+ case 25:
+ offset = fRequestKeyRequest (tvb, tree, offset);
+ break;
+ case 26:
+ offset = fReadRangeRequest (tvb, tree, offset);
+ break;
+ case 27:
+ offset = fLifeSafetyOperationRequest(tvb, tree, offset, NULL);
+ break;
+ case 28:
+ offset = fSubscribeCOVPropertyRequest(tvb, tree, offset);
+ break;
+ case 29:
+ offset = fGetEventInformationRequest (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ break;
+ }
+ return offset;
+}
+
+static guint
+fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+
+ switch (service_choice) {
+ case 3: /* confirmedEventNotificationAck */
+ offset = fGetAlarmSummaryAck (tvb, tree, offset);
+ break;
+ case 4: /* getEnrollmentSummaryAck */
+ offset = fGetEnrollmentSummaryAck (tvb, tree, offset);
+ break;
+ case 6: /* atomicReadFile */
+ offset = fAtomicReadFileAck (tvb, tree, offset);
+ break;
+ case 7: /* atomicReadFileAck */
+ offset = fAtomicWriteFileAck (tvb, tree, offset);
+ break;
+ case 10: /* createObject */
+ offset = fCreateObjectAck (tvb, tree, offset);
+ break;
+ case 12:
+ offset = fReadPropertyAck (tvb, tree, offset);
+ break;
+ case 13:
+ offset = fReadPropertyConditionalAck (tvb, tree, offset);
+ break;
+ case 14:
+ offset = fReadPropertyMultipleAck (tvb, tree, offset);
+ break;
+ case 18:
+ offset = fConfirmedPrivateTransferAck(tvb, tree, offset);
+ break;
+ case 21:
+ offset = fVtOpenAck (tvb, tree, offset);
+ break;
+ case 23:
+ offset = fVtDataAck (tvb, tree, offset);
+ break;
+ case 24:
+ offset = fAuthenticateAck (tvb, tree, offset);
+ break;
+ case 26:
+ offset = fReadRangeAck (tvb, tree, offset);
+ break;
+ case 29:
+ offset = fGetEventInformationACK (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ }
+ return offset;
+}
+
+static guint
+fIAmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint8 tmp, tag_no, class_tag, i;
+ guint32 lvt, val = 0;
+
+ /* BACnetObjectIdentifier */
+ offset = fApplicationTypes (tvb, tree, offset, "BACnet Object Identifier: ", NULL);
+
+ /* MaxAPDULengthAccepted */
+ offset = fApplicationTypes (tvb, tree, offset, "Maximum ADPU Length accepted: ", NULL);
+
+ /* segmentationSupported */
+ fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
+ offset++; /* set offset according to enhancements.... */
+ for (i = 0; i < min(lvt, 4); i++) {
+ tmp = tvb_get_guint8(tvb, offset+i);
+ val = (val << 8) + tmp;
+ }
+ proto_tree_add_text(tree, tvb, offset, 1, "segmentation Supported: %s", val_to_str(val, BACnetSegmentation, "segmentation (%d) not found"));
+ offset+=lvt;
+
+ /* vendor ID */
+ return fUnsignedTag (tvb, tree, offset, "vendor ID: ");
+}
+
+static guint
+fIHaveRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ /* BACnetDeviceIdentifier */
+ offset = fApplicationTypes (tvb, tree, offset, "Device Identifier: ", NULL);
+
+ /* BACnetObjectIdentifier */
+ offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: ", NULL);
+
+ /* ObjectName */
+ return fApplicationTypes (tvb, tree, offset, "Object Name: ", NULL);
+
+}
+
+static guint
+fWhoIsRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* DeviceInstanceRangeLowLimit Optional */
+ offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range Low Limit: ");
+ break;
+ case 1: /* DeviceInstanceRangeHighLimit Optional but required if DeviceInstanceRangeLowLimit is there */
+ offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range High Limit: ");
+ break;
+ default:
+ return offset;
+ break;
+ }
+ }
+ return offset;
+}
+
+static guint
+fUnconfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
+{
+ if (offset >= tvb_reported_length(tvb))
+ return offset;
+
+ switch (service_choice) {
+ case 0: /* I-Am-Request */
+ offset = fIAmRequest (tvb, tree, offset);
+ break;
+ case 1: /* i-Have Request */
+ offset = fIHaveRequest (tvb, tree, offset);
+ break;
+ case 2: /* unconfirmedCOVNotification */
+ offset = fUnconfirmedCOVNotificationRequest (tvb, tree, offset);
+ break;
+ case 3: /* unconfirmedEventNotification */
+ offset = fUnconfirmedEventNotificationRequest (tvb, tree, offset);
+ break;
+ case 4: /* unconfirmedPrivateTransfer */
+ offset = fUnconfirmedPrivateTransferRequest(tvb, tree, offset);
+ break;
+ case 5: /* unconfirmedTextMessage */
+ offset = fUnconfirmedTextMessageRequest(tvb, tree, offset);
+ break;
+ case 6: /* timeSynchronization */
+ offset = fTimeSynchronizationRequest (tvb, tree, offset);
+ break;
+ case 7: /* who-Has */
+ offset = fWhoHas (tvb, tree, offset);
+ break;
+ case 8: /* who-Is */
+ offset = fWhoIsRequest (tvb, tree, offset);
+ break;
+ case 9: /* utcTimeSynchronization */
+ offset = fUTCTimeSynchronizationRequest (tvb, tree, offset);
+ break;
+ default:
+ break;
+ }
+ return offset;
+}
+
+static guint
+fConfirmedRequestPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{ /* BACnet-Confirmed-Request */
+ /* ASHRAE 135-2001 20.1.2 */
+
+ proto_item *tc, *tt, *ti;
+ proto_tree *bacapp_tree, *bacapp_tree_control, *bacapp_tree_tag;
+ gint tmp, bacapp_type, service_choice;
+
+ tmp = (gint) tvb_get_guint8(tvb, offset);
+ bacapp_type = (tmp >> 4) & 0x0f;
+ bacapp_flags = tmp & 0x0f;
+
+ service_choice = (gint) tvb_get_guint8(tvb, offset+3);
+ if (bacapp_flags & 0x08)
+ service_choice = (gint) tvb_get_guint8(tvb, offset+5);
+
+ ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
+ bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+ tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
+ bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+ proto_tree_add_item(bacapp_tree_control, hf_bacapp_SEG, tvb, offset, 1, TRUE);
+ proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, offset, 1, TRUE);
+ proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree_control, hf_bacapp_response_segments, tvb,
+ offset, 1, TRUE);
+ proto_tree_add_item(bacapp_tree_control, hf_bacapp_max_adpu_size, tvb,
+ offset, 1, TRUE);
+ offset++;
+ proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
+ if (bacapp_flags & 0x08) {
+ bacapp_seq = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(bacapp_tree_control, hf_bacapp_sequence_number, tvb,
+ offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree_control, hf_bacapp_window_size, tvb,
+ offset++, 1, TRUE);
}
+ tmp = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+ offset++, 1, TRUE);
+ tt = proto_tree_add_item(bacapp_tree, hf_bacapp_vpart, tvb,
+ offset, 0, TRUE);
+ /* Service Request follows... Variable Encoding 20.2ff */
+ bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
+ return fConfirmedServiceRequest (tvb, bacapp_tree_tag, offset, tmp);
+}
- return max_segs;
+static guint
+fUnconfirmedRequestPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{ /* BACnet-Unconfirmed-Request-PDU */
+ /* ASHRAE 135-2001 20.1.3 */
+
+ proto_item *tt, *ti;
+ proto_tree *bacapp_tree_tag, *bacapp_tree;
+ gint tmp;
+
+ tmp = tvb_get_guint8(tvb, offset+1);
+
+ ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
+ bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+ proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
+
+ tmp = tvb_get_guint8(tvb, offset);
+ tt = proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb,
+ offset++, 1, TRUE);
+ /* Service Request follows... Variable Encoding 20.2ff */
+ bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
+ return fUnconfirmedServiceRequest (tvb, bacapp_tree_tag, offset, tmp);
}
-/* from clause 20.1.2.5 max-APDU-length-accepted
- returns the decoded value
-
- max-APDU-length-accepted
- B'0000' Up to MinimumMessageSize (50 octets)
- B'0001' Up to 128 octets
- B'0010' Up to 206 octets (fits in a LonTalk frame)
- B'0011' Up to 480 octets (fits in an ARCNET frame)
- B'0100' Up to 1024 octets
- B'0101' Up to 1476 octets (fits in an ISO 8802-3 frame)
- B'0110' reserved by ASHRAE
- B'0111' reserved by ASHRAE
- B'1000' reserved by ASHRAE
- B'1001' reserved by ASHRAE
- B'1010' reserved by ASHRAE
- B'1011' reserved by ASHRAE
- B'1100' reserved by ASHRAE
- B'1101' reserved by ASHRAE
- B'1110' reserved by ASHRAE
- B'1111' reserved by ASHRAE
-*/
-static guint16 decode_max_apdu(guint8 octet)
-{
- guint16 max_apdu = 0;
-
- switch (octet & 0x0F)
- {
- case 0:
- max_apdu = 50;
- break;
- case 1:
- max_apdu = 128;
- break;
- case 2:
- max_apdu = 206;
- break;
- case 3:
- max_apdu = 480;
+static guint
+fSimpleAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{ /* BACnet-Simple-Ack-PDU */
+ /* ASHRAE 135-2001 20.1.4 */
+
+ proto_item *tc, *ti;
+ gint tmp;
+ proto_tree *bacapp_tree;
+
+ tmp = tvb_get_guint8(tvb, offset+2);
+
+ ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
+ bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+ tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
+
+ proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+ offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+ offset++, 1, TRUE);
+ return offset;
+}
+
+static guint
+fComplexAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{ /* BACnet-Complex-Ack-PDU */
+ /* ASHRAE 135-2001 20.1.5 */
+
+ proto_item *tc, *tt, *ti;
+ proto_tree *bacapp_tree, *bacapp_tree_control, *bacapp_tree_tag;
+ gint tmp, bacapp_type;
+
+ tmp = (gint) tvb_get_guint8(tvb, offset);
+ bacapp_type = (tmp >> 4) & 0x0f;
+ bacapp_flags = tmp & 0x0f;
+
+ tmp = tvb_get_guint8(tvb, offset+2);
+ if (bacapp_flags & 0x08)
+ tmp = tvb_get_guint8(tvb, offset+4);
+
+ ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
+ bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+ tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
+ bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+ proto_tree_add_item(bacapp_tree, hf_bacapp_SEG, tvb, offset, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_MOR, tvb, offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+ offset++, 1, TRUE);
+ if (bacapp_flags & 0x08) {
+ bacapp_seq = tvb_get_guint8(tvb, offset);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
+ offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
+ offset++, 1, TRUE);
+ }
+ tmp = tvb_get_guint8(tvb, offset);
+ tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+ offset++, 1, TRUE);
+ /* Service ACK follows... */
+ bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
+ return fConfirmedServiceAck (tvb, bacapp_tree_tag, offset, tmp);
+}
+
+
+static guint
+fSegmentAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{ /* BACnet-SegmentAck-PDU */
+ /* ASHRAE 135-2001 20.1.6 */
+
+ proto_item *tc, *ti;
+ proto_tree *bacapp_tree_control, *bacapp_tree;
+
+ ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
+ bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+ tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
+ bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+ proto_tree_add_item(bacapp_tree, hf_bacapp_NAK, tvb, offset, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+ offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
+ offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
+ offset++, 1, TRUE);
+ return offset;
+}
+
+static guint
+fConfirmedPrivateTransferError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* errorType */
+ offset = fError (tvb,tree,offset);
+ break;
+ case 1: /* vendorID */
+ offset = fUnsignedTag (tvb,tree,offset,"vendor ID: ");
+ break;
+ case 2: /* serviceNumber */
+ offset = fUnsignedTag (tvb,tree,offset,"service Number: ");
+ break;
+ case 3: /* errorParameters */
+ offset = fAbstractSyntaxNType (tvb, tree, offset);
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fCreateObjectError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* errorType */
+ offset = fError (tvb,tree,offset);
+ break;
+ case 1: /* firstFailedElementNumber */
+ offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* errorType */
+ offset = fError (tvb,tree,offset);
+ break;
+ case 1: /* firstFailedElementNumber */
+ offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fVTSession(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ if (offset < tvb_reported_length(tvb)) { /* don't loop */
+ offset = fUnsignedTag (tvb,tree,offset, "local-VTSessionID: ");
+ offset = fUnsignedTag (tvb,tree,offset, "remote-VTSessionID: ");
+ offset = fAddress (tvb,tree,offset);
+ }
+ return offset;
+}
+
+static guint
+fVTCloseError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* errorType */
+ offset = fError (tvb,tree,offset);
+ break;
+ case 1: /* listOfVTSessionIdentifiers */
+ offset = fUnsignedTag (tvb,tree,offset,"VT SessionID: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fWritePropertyMultipleError(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ guint lastoffset = 0;
+
+ while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
+ lastoffset = offset;
+ switch (fTagNo(tvb, offset)) {
+ case 0: /* errorType */
+ offset = fError (tvb,tree,offset);
+ break;
+ case 1: /* firstFailedWriteAttempt */
+ offset = fUnsignedTag (tvb,tree,offset,"first failed write attempt: ");
+ break;
+ default:
+ return offset;
+ }
+ }
+ return offset;
+}
+
+static guint
+fError (tvbuff_t *tvb, proto_tree *tree, guint offset)
+{
+ offset = fApplicationTypes (tvb, tree, offset, "error Class: ", BACnetErrorClass);
+ return fApplicationTypes (tvb, tree, offset, "error Code: ", BACnetErrorCode);
+}
+
+static guint
+fBACnetError (tvbuff_t *tvb, proto_tree *tree, guint offset, guint service)
+{
+ switch (service) {
+ case 8: /* no break here !!!! */
+ case 9:
+ offset = fChangeListError (tvb, tree, offset);
break;
- case 4:
- max_apdu = 1024;
+ case 10:
+ offset = fCreateObjectError (tvb,tree,offset);
break;
- case 5:
- max_apdu = 1476;
+ case 16:
+ offset = fWritePropertyMultipleError (tvb,tree,offset);
break;
- default:
+ case 18:
+ offset = fConfirmedPrivateTransferError (tvb,tree,offset);
+ case 22:
+ offset = fVTCloseError (tvb,tree,offset);
+ default:
+ return fError (tvb, tree, offset);
break;
}
+ return offset;
+}
+
+static guint
+fErrorPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{ /* BACnet-Error-PDU */
+ /* ASHRAE 135-2001 20.1.7 */
- return max_apdu;
+ proto_item *tc, *ti, *tt;
+ proto_tree *bacapp_tree_control, *bacapp_tree, *bacapp_tree_tag;
+ guint8 tmp;
+
+ ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
+ bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+ tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
+ bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
+
+ proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+ offset++, 1, TRUE);
+ tmp = tvb_get_guint8(tvb, offset);
+ tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
+ offset++, 1, TRUE);
+ /* Error Handling follows... */
+ bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
+ return fBACnetError (tvb, bacapp_tree_tag, offset, tmp);
}
-#define BACAPP_SEGMENTED_REQUEST 0x08
-static const true_false_string tfs_segmented_request = {
- "Segmented Request.",
- "Unsegmented Request."
-};
-#define BACAPP_MORE_SEGMENTS 0x04
-static const true_false_string tfs_more_segments = {
- "More Segments Follow.",
- "No More Segments Follow."
-};
-#define BACAPP_SEGMENTED_RESPONSE 0x02
-static const true_false_string tfs_segmented_response = {
- "Segmented Response Accepted.",
- "Segmented Response Not Accepted."
-};
-#define BACAPP_SEGMENT_NAK 0x02
-static const true_false_string tfs_segment_nak = {
- "Negative Acknowledgement. Segment out of Order.",
- "Normal Acknowledgement."
-};
-#define BACAPP_SENT_BY 0x01
-static const true_false_string tfs_sent_by = {
- "Sent By Server.",
- "Sent By Client."
-};
-static const true_false_string tfs_reserved_bit = {
- "Shall be zero, but is one.",
- "Shall be zero and is zero."
-};
+static guint
+fRejectPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{ /* BACnet-Reject-PDU */
+ /* ASHRAE 135-2001 20.1.8 */
-static int proto_bacapp = -1;
+ proto_item *tc, *ti;
+ proto_tree *bacapp_tree_control, *bacapp_tree;
-static int hf_bacapp_type = -1;
-static int hf_bacapp_segmented_request = -1;
-static int hf_bacapp_more_segments = -1;
-static int hf_bacapp_segmented_response = -1;
-static int hf_bacapp_max_segments = -1;
-static int hf_bacapp_max_response = -1;
-static int hf_bacapp_invoke_id = -1;
-static int hf_bacapp_sequence_number = -1;
-static int hf_bacapp_window_size = -1;
-static int hf_bacapp_service_choice = -1;
-static int hf_bacapp_segment_nak = -1;
-static int hf_bacapp_sent_by = -1;
-static int hf_bacapp_error_choice = -1;
-static int hf_bacapp_reject_reason = -1;
-static int hf_bacapp_abort_reason = -1;
-/* generic reserved bits */
-static int hf_bacapp_reserved_bit_0 = -1;
-static int hf_bacapp_reserved_bit_1 = -1;
-static int hf_bacapp_reserved_bit_2 = -1;
-static int hf_bacapp_reserved_bit_3 = -1;
-static int hf_bacapp_reserved_bit_4 = -1;
-static int hf_bacapp_reserved_bit_5 = -1;
-static int hf_bacapp_reserved_bit_6 = -1;
-static int hf_bacapp_reserved_bit_7 = -1;
+ ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
+ bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
-static gint ett_bacapp = -1;
+ tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
+ bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
-static dissector_handle_t data_handle;
+ proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+ offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_BACnetRejectReason, tvb,
+ offset++, 1, TRUE);
+ return offset;
+}
+
+static guint
+fAbortPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
+{ /* BACnet-Abort-PDU */
+ /* ASHRAE 135-2001 20.1.9 */
+
+ proto_item *tc, *ti;
+ proto_tree *bacapp_tree_control, *bacapp_tree;
+
+ ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
+ bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+
+ tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
+ bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
-static void
+ proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
+ offset++, 1, TRUE);
+ proto_tree_add_item(bacapp_tree, hf_BACnetAbortReason, tvb,
+ offset++, 1, TRUE);
+ return offset;
+}
+
+void
dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- proto_item *ti;
- proto_tree *bacapp_tree;
- guint8 offset;
- guint8 bacapp_type;
- guint8 bacapp_type_seg;
- guint8 bacapp_service;
- guint8 bacapp_reason;
- guint8 bacapp_max_seg_resp;
- guint8 bacapp_invoke_id;
- guint8 bacapp_sequence_number;
- guint8 bacapp_window_size;
- guint8 max_segs;
- guint16 max_apdu;
+ gint8 tmp, bacapp_type;
tvbuff_t *next_tvb;
+ guint offset = 0;
+ guint8 bacapp_service, bacapp_reason;
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU");
if (check_col(pinfo->cinfo, COL_INFO))
col_add_str(pinfo->cinfo, COL_INFO, "BACnet APDU ");
-
- offset = 0;
- bacapp_type_seg = tvb_get_guint8(tvb, offset);
- bacapp_type = (bacapp_type_seg >> 4) & 0xf;
+ tmp = (gint) tvb_get_guint8(tvb, 0);
+ bacapp_type = (tmp >> 4) & 0x0f;
+
/* show some descriptive text in the INFO column */
if (check_col(pinfo->cinfo, COL_INFO))
{
col_clear(pinfo->cinfo, COL_INFO);
col_add_str(pinfo->cinfo, COL_INFO,
- val_to_str(bacapp_type, bacapp_type_names, bacapp_unknown_str));
+ val_to_str(bacapp_type, BACnetTypeName, "#### unknown APDU ##### "));
switch (bacapp_type)
{
case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
/* segmented messages have 2 additional bytes */
- if (bacapp_type_seg & BACAPP_SEGMENTED_REQUEST)
+ if (tmp & BACAPP_SEGMENTED_REQUEST)
bacapp_service = tvb_get_guint8(tvb, offset + 5);
else
bacapp_service = tvb_get_guint8(tvb, offset + 3);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
- bacapp_confirmed_service_names,
+ BACnetConfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:
bacapp_service = tvb_get_guint8(tvb, offset + 1);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
- bacapp_unconfirmed_service_names,
+ BACnetUnconfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_SIMPLE_ACK:
bacapp_service = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
- bacapp_confirmed_service_names,
+ BACnetConfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_COMPLEX_ACK:
/* segmented messages have 2 additional bytes */
- if (bacapp_type_seg & BACAPP_SEGMENTED_REQUEST)
+ if (tmp & BACAPP_SEGMENTED_REQUEST)
bacapp_service = tvb_get_guint8(tvb, offset + 4);
else
bacapp_service = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
- bacapp_confirmed_service_names,
+ BACnetConfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_SEGMENT_ACK:
@@ -409,18 +5051,22 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
bacapp_service = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
- bacapp_confirmed_service_names,
+ BACnetConfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_REJECT:
bacapp_reason = tvb_get_guint8(tvb, offset + 2);
- col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
- bacapp_reject_reason_name(bacapp_reason));
+ col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
+ val_to_str(bacapp_reason,
+ BACnetRejectReason,
+ bacapp_unknown_service_str));
break;
case BACAPP_TYPE_ABORT:
bacapp_reason = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
- bacapp_abort_reason_name(bacapp_reason));
+ val_to_str(bacapp_reason,
+ BACnetAbortReason,
+ bacapp_unknown_service_str));
break;
/* UNKNOWN */
default:
@@ -429,395 +5075,151 @@ dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
}
- if (tree) {
- ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
-
- bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
+ if (tree) {
+ /* ASHRAE 135-2001 20.1.1 */
+ switch (bacapp_type) {
+ case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: /* BACnet-Confirmed-Service-Request */
+ offset = fConfirmedRequestPDU(tvb, tree, offset);
+ break;
+ case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST: /* BACnet-Unconfirmed-Request-PDU */
+ offset = fUnconfirmedRequestPDU(tvb, tree, offset);
+ break;
+ case BACAPP_TYPE_SIMPLE_ACK: /* BACnet-Simple-Ack-PDU */
+ offset = fSimpleAckPDU(tvb, tree, offset);
+ break;
+ case BACAPP_TYPE_COMPLEX_ACK: /* BACnet-Complex-Ack-PDU */
+ offset = fComplexAckPDU(tvb, tree, offset);
+ break;
+ case BACAPP_TYPE_SEGMENT_ACK: /* BACnet-SegmentAck-PDU */
+ offset = fSegmentAckPDU(tvb, tree, offset);
+ break;
+ case BACAPP_TYPE_ERROR: /* BACnet-Error-PDU */
+ offset = fErrorPDU(tvb, tree, offset);
+ break;
+ case BACAPP_TYPE_REJECT: /* BACnet-Reject-PDU */
+ offset = fRejectPDU(tvb, tree, offset);
+ break;
+ case BACAPP_TYPE_ABORT: /* BACnet-Abort-PDU */
+ offset = fAbortPDU(tvb, tree, offset);
+ break;
+ }
+ }
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_type, tvb,
- offset, 1, bacapp_type, "APDU Type: %u (%s)", bacapp_type,
- val_to_str(bacapp_type, bacapp_type_names, bacapp_unknown_str));
- switch (bacapp_type)
- {
- case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_segmented_request,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_more_segments,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_segmented_response,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_0,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- bacapp_max_seg_resp = tvb_get_guint8(tvb, offset);
- max_segs = decode_max_segs(bacapp_max_seg_resp);
- if (max_segs > 64)
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_max_segments,
- tvb, offset, 1, bacapp_max_seg_resp,
- "Maximum Segments Accepted: %u "
- "(Greater than 64 segments accepted).",
- ((bacapp_max_seg_resp >> 4) & 0x0f));
- else
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_max_segments,
- tvb, offset, 1, bacapp_max_seg_resp,
- "Maximum Segments Accepted: %u (%u segments accepted).",
- ((bacapp_max_seg_resp >> 4) & 0x0f), max_segs);
- max_apdu = decode_max_apdu(bacapp_max_seg_resp);
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_max_response,
- tvb, offset, 1, bacapp_max_seg_resp,
- "Maximum APDU Accepted: %u (%u octets)",
- bacapp_max_seg_resp,max_apdu);
- offset++;
- bacapp_invoke_id = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id,
- tvb, offset, 1, bacapp_invoke_id);
- offset++;
- /* segmented messages have 2 additional bytes */
- if (bacapp_type_seg & BACAPP_SEGMENTED_REQUEST)
- {
- bacapp_sequence_number = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_sequence_number,
- tvb, offset, 1, bacapp_sequence_number);
- offset++;
- bacapp_window_size = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_window_size,
- tvb, offset, 1, bacapp_window_size);
- offset++;
- }
- bacapp_service = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_service_choice,
- tvb, offset, 1, bacapp_service,
- "Service Choice: %u (%s)", bacapp_service,
- val_to_str(bacapp_service,
- bacapp_confirmed_service_names,
- bacapp_unknown_service_str));
- offset++;
- break;
- case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_3,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_2,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_1,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_0,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- bacapp_service = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_service_choice,
- tvb, offset, 1, bacapp_service,
- "Service Choice: %u (%s)", bacapp_service,
- val_to_str(bacapp_service,
- bacapp_unconfirmed_service_names,
- bacapp_unknown_service_str));
- offset++;
- break;
- case BACAPP_TYPE_SIMPLE_ACK:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_3,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_2,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_1,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_0,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- bacapp_invoke_id = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id,
- tvb, offset, 1, bacapp_invoke_id);
- offset++;
- bacapp_service = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_service_choice,
- tvb, offset, 1, bacapp_service,
- "Service Choice: %u (%s)", bacapp_service,
- val_to_str(bacapp_service,
- bacapp_confirmed_service_names,
- bacapp_unknown_service_str));
- offset++;
- break;
- case BACAPP_TYPE_COMPLEX_ACK:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_segmented_request,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_more_segments,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_1,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_0,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- bacapp_invoke_id = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id,
- tvb, offset, 1, bacapp_invoke_id);
- offset++;
- /* segmented messages have 2 additional bytes */
- if (bacapp_type_seg & BACAPP_SEGMENTED_REQUEST)
- {
- bacapp_sequence_number = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_sequence_number,
- tvb, offset, 1, bacapp_sequence_number);
- offset++;
- bacapp_window_size = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_window_size,
- tvb, offset, 1, bacapp_window_size);
- offset++;
- }
- bacapp_service = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_service_choice,
- tvb, offset, 1, bacapp_service,
- "Service Choice: %u (%s)", bacapp_service,
- val_to_str(bacapp_service,
- bacapp_confirmed_service_names,
- bacapp_unknown_service_str));
- offset++;
- break;
- case BACAPP_TYPE_SEGMENT_ACK:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_3,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_2,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_segment_nak,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_sent_by,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- bacapp_invoke_id = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id,
- tvb, offset, 1, bacapp_invoke_id);
- offset++;
- bacapp_sequence_number = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_sequence_number,
- tvb, offset, 1, bacapp_sequence_number);
- offset++;
- bacapp_window_size = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_window_size,
- tvb, offset, 1, bacapp_window_size);
- offset++;
- break;
- case BACAPP_TYPE_ERROR:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_3,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_2,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_1,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_0,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- bacapp_invoke_id = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id,
- tvb, offset, 1, bacapp_invoke_id);
- offset++;
- bacapp_service = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_error_choice,
- tvb, offset, 1, bacapp_service,
- "Error Choice: %u (%s)", bacapp_service,
- val_to_str(bacapp_service,
- bacapp_confirmed_service_names,
- bacapp_unknown_service_str));
- offset++;
- break;
- case BACAPP_TYPE_REJECT:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_3,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_2,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_1,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_0,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- bacapp_invoke_id = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id,
- tvb, offset, 1, bacapp_invoke_id);
- offset++;
- bacapp_reason = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_reject_reason,
- tvb, offset, 1, bacapp_reason,
- "Reject Reason: %u (%s)", bacapp_reason,
- bacapp_reject_reason_name(bacapp_reason));
- offset++;
- break;
- case BACAPP_TYPE_ABORT:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_3,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_2,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_1,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_0,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- bacapp_invoke_id = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint(bacapp_tree, hf_bacapp_invoke_id,
- tvb, offset, 1, bacapp_invoke_id);
- offset++;
- bacapp_reason = tvb_get_guint8(tvb, offset);
- proto_tree_add_uint_format(bacapp_tree, hf_bacapp_reject_reason,
- tvb, offset, 1, bacapp_reason,
- "Abort Reason: %u (%s)", bacapp_reason,
- bacapp_abort_reason_name(bacapp_reason));
- offset++;
- break;
- default:
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_3,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_2,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_1,
- tvb, offset, 1, bacapp_type_seg);
- proto_tree_add_boolean(bacapp_tree, hf_bacapp_reserved_bit_0,
- tvb, offset, 1, bacapp_type_seg);
- offset++;
- break;
- }
- }
- next_tvb = tvb_new_subset(tvb,offset,-1,-1);
+ next_tvb = tvb_new_subset(tvb,offset,-1,tvb_reported_length(tvb) - offset);
call_dissector(data_handle,next_tvb, pinfo, tree);
}
-
void
proto_register_bacapp(void)
{
static hf_register_info hf[] = {
{ &hf_bacapp_type,
- { "APDU Type",
- "bacapp.apdu_type",
- FT_UINT8, BASE_DEC, NULL, 0xf0, "APDU Type", HFILL }
+ { "APDU Type", "bacapp.type",
+ FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, "APDU Type", HFILL }
+ },
+ { &hf_bacapp_SEG,
+ { "Segmented Request", "bacapp.segmented_request",
+ FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, "Segmented Request", HFILL }
},
- { &hf_bacapp_segmented_request,
- { "Segmented Request",
- "bacapp.segmented_request",
- FT_BOOLEAN, 8, TFS(&tfs_segmented_request),
- BACAPP_SEGMENTED_REQUEST, "Segmented Request", HFILL }
+ { &hf_bacapp_MOR,
+ { "More Segments", "bacapp.more_segments",
+ FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL }
},
- { &hf_bacapp_more_segments,
- { "More Segments",
- "bacapp.more_segments",
- FT_BOOLEAN, 8, TFS(&tfs_more_segments),
- BACAPP_MORE_SEGMENTS, "More Segments", HFILL }
+ { &hf_bacapp_SA,
+ { "SA", "bacapp.SA",
+ FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL }
},
- { &hf_bacapp_segmented_response,
- { "Segmented Response",
- "bacapp.segmented_response",
- FT_BOOLEAN, 8, TFS(&tfs_segmented_response),
- BACAPP_SEGMENTED_RESPONSE, "Segmented Response", HFILL }
+ { &hf_bacapp_max_adpu_size,
+ { "Size of Maximum ADPU accepted", "bacapp.max_adpu_size",
+ FT_UINT8, BASE_DEC, VALS(BACnetMaxAPDULengthAccepted), 0x0f, "Size of Maximum ADPU accepted", HFILL }
},
- { &hf_bacapp_max_segments,
- { "Maximum Segments Accepted",
- "bacapp.max_segments_accepted",
- FT_UINT8, BASE_DEC, NULL, 0x70, "Maximum Segments Accepted", HFILL }
+ { &hf_bacapp_response_segments,
+ { "Max Response Segments accepted", "bacapp.response_segments",
+ FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0xe0, "Max Response Segments accepted", HFILL }
},
- { &hf_bacapp_max_response,
- { "Maximum APDU accepted",
- "bacapp.max_apdu_accepted",
- FT_UINT8, BASE_DEC, NULL, 0x0f, "Maximum APDU accepted", HFILL }
+ { &hf_bacapp_objectType,
+ { "Object Type", "bacapp.objectType",
+ FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, "Object Type", HFILL }
+ },
+ { &hf_bacapp_instanceNumber,
+ { "Instance Number", "bacapp.instance_number",
+ FT_UINT32, BASE_DEC, NULL, 0x003fffff, "Instance Number", HFILL }
},
{ &hf_bacapp_invoke_id,
- { "Invoke ID",
- "bacapp.invoke_id",
- FT_UINT8, BASE_DEC, NULL, 0, "Invoke ID", HFILL }
+ { "Invoke ID", "bacapp.invoke_id",
+ FT_UINT8, BASE_HEX, NULL, 0, "Invoke ID", HFILL }
},
{ &hf_bacapp_sequence_number,
- { "Sequence Number",
- "bacapp.segment_sequence_number",
+ { "Sequence Number", "bacapp.sequence_number",
FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL }
},
{ &hf_bacapp_window_size,
- { "Proposed Window Size",
- "bacapp.segment_window_size",
+ { "Proposed Window Size", "bacapp.window_size",
FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL }
},
- { &hf_bacapp_service_choice,
- { "Service Choice",
- "bacapp.service_choice",
- FT_UINT8, BASE_DEC, NULL, 0, "Service Choice", HFILL }
- },
- { &hf_bacapp_segment_nak,
- { "Segment NAK",
- "bacapp.segment_nak",
- FT_BOOLEAN, 8, TFS(&tfs_segment_nak),
- BACAPP_SEGMENT_NAK, "Segment NAK", HFILL }
+ { &hf_bacapp_service,
+ { "Service Choice", "bacapp.confirmed_service",
+ FT_UINT8, BASE_DEC, VALS(BACnetConfirmedServiceChoice), 0x00, "Service Choice", HFILL }
},
- { &hf_bacapp_sent_by,
- { "Sent By",
- "bacapp.segment_sent_by",
- FT_BOOLEAN, 8, TFS(&tfs_sent_by),
- BACAPP_SENT_BY, "Sent By", HFILL }
+ { &hf_bacapp_uservice,
+ { "Unconfirmed Service Choice", "bacapp.unconfirmed_service",
+ FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, "Unconfirmed Service Choice", HFILL }
},
- { &hf_bacapp_error_choice,
- { "Error Choice",
- "bacapp.error_choice",
- FT_UINT8, BASE_DEC, NULL, 0, "Error Choice", HFILL }
+ { &hf_bacapp_NAK,
+ { "NAK", "bacapp.NAK",
+ FT_BOOLEAN, 8, NULL, 0x02, "negativ ACK", HFILL }
},
- { &hf_bacapp_reject_reason,
- { "Reject Reason",
- "bacapp.reject_reason",
- FT_UINT8, BASE_DEC, NULL, 0, "Reject Reason", HFILL }
+ { &hf_bacapp_SRV,
+ { "SRV", "bacapp.SRV",
+ FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL }
},
- { &hf_bacapp_abort_reason,
- { "Abort Reason",
- "bacapp.abort_reason",
- FT_UINT8, BASE_DEC, NULL, 0, "Abort Reason", HFILL }
+ { &hf_BACnetRejectReason,
+ { "Reject Reason", "bacapp.reject_reason",
+ FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, "Reject Reason", HFILL }
},
- { &hf_bacapp_reserved_bit_0,
- { "Reserved Bit 0",
- "bacapp.reserved_bit_0",
- FT_BOOLEAN, 8, TFS(&tfs_reserved_bit),
- 0x01, "Reserved Bit 0", HFILL }
+ { &hf_BACnetAbortReason,
+ { "Abort Reason", "bacapp.abort_reason",
+ FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 0x00, "Abort Reason", HFILL }
},
- { &hf_bacapp_reserved_bit_1,
- { "Reserved Bit 1",
- "bacapp.reserved_bit_1",
- FT_BOOLEAN, 8, TFS(&tfs_reserved_bit),
- 0x02, "Reserved Bit 1", HFILL }
+ { &hf_bacapp_vpart,
+ { "BACnet APDU variable part:", "bacapp.variable_part",
+ FT_NONE, 0, NULL, 00, "BACnet APDU varaiable part", HFILL }
},
- { &hf_bacapp_reserved_bit_2,
- { "Reserved Bit 2",
- "bacapp.reserved_bit_2",
- FT_BOOLEAN, 8, TFS(&tfs_reserved_bit),
- 0x04, "Reserved Bit 2", HFILL }
+ { &hf_BACnetTagNumber,
+ { "Tag Number", "bacapp.tag_number",
+ FT_UINT8, BASE_DEC, VALS(BACnetTagNumber), 0xF0, "Tag Number", HFILL }
},
- { &hf_bacapp_reserved_bit_3,
- { "Reserved Bit 3",
- "bacapp.reserved_bit_3",
- FT_BOOLEAN, 8, TFS(&tfs_reserved_bit),
- 0x08, "Reserved Bit 3", HFILL }
+ { &hf_BACnetTagClass,
+ { "Class", "bacapp.class",
+ FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, "Class", HFILL }
},
- { &hf_bacapp_reserved_bit_4,
- { "Reserved Bit 4",
- "bacapp.reserved_bit_4",
- FT_BOOLEAN, 8, TFS(&tfs_reserved_bit),
- 0x10, "Reserved Bit 4", HFILL }
+ { &hf_bacapp_tag_lvt,
+ { "Length Value Type", "bacapp.LVT",
+ FT_UINT8, BASE_DEC, NULL, 0x07, "Length Value Type", HFILL }
},
- { &hf_bacapp_reserved_bit_5,
- { "Reserved Bit 5",
- "bacapp.reserved_bit_5",
- FT_BOOLEAN, 8, TFS(&tfs_reserved_bit),
- 0x20, "Reserved Bit 5", HFILL }
+ { &hf_bacapp_tag_ProcessId,
+ { "ProcessIdentifier", "bacapp.processId",
+ FT_UINT32, BASE_DEC, NULL, 0, "Process Identifier", HFILL }
},
- { &hf_bacapp_reserved_bit_6,
- { "Reserved Bit 6",
- "bacapp.reserved_bit_6",
- FT_BOOLEAN, 8, TFS(&tfs_reserved_bit),
- 0x40, "Reserved Bit 6", HFILL }
- },
- { &hf_bacapp_reserved_bit_7,
- { "Reserved Bit 7",
- "bacapp.reserved_bit_7",
- FT_BOOLEAN, 8, TFS(&tfs_reserved_bit),
- 0x80, "Reserved Bit 7", HFILL }
+ { &hf_bacapp_tag_initiatingObjectType,
+ { "ObjectType", "bacapp.objectType",
+ FT_UINT16, BASE_DEC, VALS(BACnetObjectType), 0x00, "Object Type", HFILL }
},
};
-
static gint *ett[] = {
&ett_bacapp,
+ &ett_bacapp_control,
+ &ett_bacapp_tag,
+ &ett_bacapp_list,
+ &ett_bacapp_value,
};
proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU",
"BACapp", "bacapp");
+
proto_register_field_array(proto_bacapp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
register_dissector("bacapp", dissect_bacapp, proto_bacapp);
+
}
void
@@ -826,3 +5228,32 @@ proto_reg_handoff_bacapp(void)
data_handle = find_dissector("data");
}
+guint32
+fConvertXXXtoUTF8 (guint8 *in, guint32 *inbytesleft, guint8 *out, guint32 *outbytesleft, guint8 *fromcoding)
+{ /* I don't want to let in and out be modified */
+#ifdef HAVE_CONFIG_H
+#if HAVE_ICONV_H
+ guint32 i;
+ iconv_t icd;
+ guint8 *inp = in, *outp = out;
+ guint8 **inpp = &inp, **outpp = &outp;
+
+ if ((icd = iconv_open ("UTF-8", fromcoding)) != (iconv_t) -1) {
+
+ i = iconv (icd, (char**) inpp, inbytesleft, (char**) outpp, outbytesleft);
+ *outpp[0] = '\0';
+ iconv_close (icd);
+ return i;
+ }
+
+#endif
+#endif
+
+ memcpy (out, in, *inbytesleft);
+ out[*inbytesleft] = '\0';
+ *outbytesleft -= *inbytesleft;
+ *inbytesleft = 0;
+
+ return 0;
+}
+
diff --git a/epan/dissectors/packet-bacapp.h b/epan/dissectors/packet-bacapp.h
new file mode 100755
index 0000000000..600bc0e6eb
--- /dev/null
+++ b/epan/dissectors/packet-bacapp.h
@@ -0,0 +1,2049 @@
+/* packet-bacapp.h
+ * Routines for BACnet (APDU) dissection
+ * Copyright 2004, Herbert Lischka <lischka@kieback-peter.de>, Berlin
+ *
+ * $Id: packet-bacapp.h,v 1.00 2004/03/11 17:50:07 Lka Exp $
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * Copied from README.developer,v 1.23
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __BACAPP_H__
+#define __BACAPP_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#if HAVE_ICONV_H
+#include <iconv.h>
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <epan/packet.h>
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifndef FAULT
+#define FAULT proto_tree_add_text(subtree, tvb, offset, tvb_length(tvb) - offset, "something is going wrong here !!"); \
+ offset = tvb_length(tvb);
+#endif
+
+#ifndef false
+#define false 0
+#endif
+#ifndef true
+#define true 1
+#endif
+
+#ifndef LABEL
+#define LABEL(lbl) (lbl==NULL ? (guint8 *) "Value: " : lbl)
+#endif
+
+
+/* BACnet PDU Types */
+#define BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST 0
+#define BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST 1
+#define BACAPP_TYPE_SIMPLE_ACK 2
+#define BACAPP_TYPE_COMPLEX_ACK 3
+#define BACAPP_TYPE_SEGMENT_ACK 4
+#define BACAPP_TYPE_ERROR 5
+#define BACAPP_TYPE_REJECT 6
+#define BACAPP_TYPE_ABORT 7
+#define MAX_BACAPP_TYPE 8
+
+#define BACAPP_SEGMENTED_REQUEST 0x08
+#define BACAPP_MORE_SEGMENTS 0x04
+#define BACAPP_SEGMENTED_RESPONSE 0x02
+#define BACAPP_SEGMENT_NAK 0x02
+#define BACAPP_SENT_BY 0x01
+
+
+/**
+ * dissect_bacapp ::= CHOICE {
+ * confirmed-request-PDU [0] BACnet-Confirmed-Request-PDU,
+ * unconfirmed-request-PDU [1] BACnet-Unconfirmed-Request-PDU,
+ * simpleACK-PDU [2] BACnet-SimpleACK-PDU,
+ * complexACK-PDU [3] BACnet-ComplexACK-PDU,
+ * segmentACK-PDU [4] BACnet-SegmentACK-PDU,
+ * error-PDU [5] BACnet-Error-PDU,
+ * reject-PDU [6] BACnet-Reject-PDU,
+ * abort-PDU [7] BACnet-Abort-PDU
+ * }
+ * @param tvb
+ * @param pinfo
+ * @param tree
+ */
+void
+dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
+
+/**
+ * ConfirmedRequest-PDU ::= SEQUENCE {
+ * pdu-type [0] Unsigned (0..15), -- 0 for this PDU Type
+ * segmentedMessage [1] BOOLEAN,
+ * moreFollows [2] BOOLEAN,
+ * segmented-response-accepted [3] BOOLEAN,
+ * reserved [4] Unsigned (0..3), -- must be set zero
+ * max-segments-accepted [5] Unsigned (0..7), -- as per 20.1.2.4
+ * max-APDU-length-accepted [5] Unsigned (0..15), -- as per 20.1.2.5
+ * invokeID [6] Unsigned (0..255),
+ * sequence-number [7] Unsigned (0..255) OPTIONAL, -- only if segmented msg
+ * proposed-window-size [8] Unsigned (0..127) OPTIONAL, -- only if segmented msg
+ * service-choice [9] BACnetConfirmedServiceChoice,
+ * service-request [10] BACnet-Confirmed-Service-Request OPTIONAL
+ * }
+ * @param tvb
+ * @param pinfo
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fConfirmedRequestPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Unconfirmed-Request-PDU ::= SEQUENCE {
+ * pdu-type [0] Unsigned (0..15), -- 1 for this PDU type
+ * reserved [1] Unsigned (0..15), -- must be set zero
+ * service-choice [2] BACnetUnconfirmedServiceChoice,
+ * service-request [3] BACnetUnconfirmedServiceRequest -- Context-specific tags 0..3 are NOT used in header encoding
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fUnconfirmedRequestPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * SimpleACK-PDU ::= SEQUENCE {
+ * pdu-type [0] Unsigned (0..15), -- 2 for this PDU type
+ * reserved [1] Unsigned (0..15), -- must be set zero
+ * invokeID [2] Unsigned (0..255),
+ * service-ACK-choice [3] BACnetUnconfirmedServiceChoice -- Context-specific tags 0..3 are NOT used in header encoding
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fSimpleAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ComplexACK-PDU ::= SEQUENCE {
+ * pdu-type [0] Unsigned (0..15), -- 3 for this PDU Type
+ * segmentedMessage [1] BOOLEAN,
+ * moreFollows [2] BOOLEAN,
+ * reserved [3] Unsigned (0..3), -- must be set zero
+ * invokeID [4] Unsigned (0..255),
+ * sequence-number [5] Unsigned (0..255) OPTIONAL, -- only if segmented msg
+ * proposed-window-size [6] Unsigned (0..127) OPTIONAL, -- only if segmented msg
+ * service-ACK-choice [7] BACnetConfirmedServiceChoice,
+ * service-ACK [8] BACnet-Confirmed-Service-Request -- Context-specific tags 0..8 are NOT used in header encoding
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fComplexAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * SegmentACK-PDU ::= SEQUENCE {
+ * pdu-type [0] Unsigned (0..15), -- 4 for this PDU Type
+ * reserved [1] Unsigned (0..3), -- must be set zero
+ * negative-ACK [2] BOOLEAN,
+ * server [3] BOOLEAN,
+ * original-invokeID [4] Unsigned (0..255),
+ * sequence-number [5] Unsigned (0..255),
+ * actual-window-size [6] Unsigned (0..127)
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fSegmentAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Error-PDU ::= SEQUENCE {
+ * pdu-type [0] Unsigned (0..15), -- 5 for this PDU Type
+ * reserved [1] Unsigned (0..3), -- must be set zero
+ * original-invokeID [2] Unsigned (0..255),
+ * error-choice [3] BACnetConfirmedServiceChoice,
+ * error [4] BACnet-Error
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fErrorPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Reject-PDU ::= SEQUENCE {
+ * pdu-type [0] Unsigned (0..15), -- 6 for this PDU Type
+ * reserved [1] Unsigned (0..3), -- must be set zero
+ * original-invokeID [2] Unsigned (0..255),
+ * reject-reason [3] BACnetRejectReason
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fRejectPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Abort-PDU ::= SEQUENCE {
+ * pdu-type [0] Unsigned (0..15), -- 7 for this PDU Type
+ * reserved [1] Unsigned (0..3), -- must be set zero
+ * server [2] BOOLEAN,
+ * original-invokeID [3] Unsigned (0..255),
+ * abort-reason [4] BACnetAbortReason
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAbortPDU(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * 20.2.4, adds the label with max 64Bit unsigned Integer Value to tree
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param label
+ * @return modified offset
+ */
+static guint
+fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);
+
+/**
+ * 20.2.5, adds the label with max 64Bit signed Integer Value to tree
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param label
+ * @return modified offset
+ */
+static guint
+fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);
+
+/**
+ * 20.2.8, adds the label with Octet String to tree; if lvt == 0 then lvt = restOfFrame
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param label
+ * @param lvt length of String
+ * @return modified offset
+ */
+static guint
+fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, guint32 lvt);
+
+/**
+ * 20.2.12, adds the label with Date Value to tree
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param label
+ * @return modified offset
+ */
+static guint
+fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);
+
+/**
+ * 20.2.13, adds the label with Time Value to tree
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param label
+ * @return modified offset
+ */
+static guint
+fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);
+
+/**
+ * 20.2.14, adds Object Identifier to tree
+ * use BIG ENDIAN: Bits 31..22 Object Type, Bits 21..0 Instance Number
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnet-Confirmed-Service-Request ::= CHOICE {
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param service_choice
+ * @return offset
+ */
+static guint
+fConfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice);
+
+/**
+ * BACnet-Confirmed-Service-ACK ::= CHOICE {
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param service_choice
+ * @return offset
+ */
+static guint
+fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice);
+
+/**
+ * AcknowledgeAlarm-Request ::= SEQUENCE {
+ * acknowledgingProcessIdentifier [0] Unsigned32,
+ * eventObjectIdentifier [1] BACnetObjectIdentifer,
+ * eventStateAcknowledge [2] BACnetEventState,
+ * timeStamp [3] BACnetTimeStamp,
+ * acknowledgementSource [4] Character String,
+ * timeOfAcknowledgement [5] BACnetTimeStamp
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAcknowlegdeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ConfirmedCOVNotification-Request ::= SEQUENCE {
+ * subscriberProcessIdentifier [0] Unsigned32,
+ * initiatingDeviceIdentifier [1] BACnetObjectIdentifer,
+ * monitoredObjectIdentifier [2] BACnetObjectIdentifer,
+ * timeRemaining [3] unsigned,
+ * listOfValues [4] SEQUENCE OF BACnetPropertyValues
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ConfirmedEventNotification-Request ::= SEQUENCE {
+ * ProcessIdentifier [0] Unsigned32,
+ * initiatingDeviceIdentifier [1] BACnetObjectIdentifer,
+ * eventObjectIdentifier [2] BACnetObjectIdentifer,
+ * timeStamp [3] BACnetTimeStamp,
+ * notificationClass [4] unsigned,
+ * priority [5] unsigned8,
+ * eventType [6] BACnetEventType,
+ * messageText [7] CharacterString OPTIONAL,
+ * notifyType [8] BACnetNotifyType,
+ * ackRequired [9] BOOLEAN OPTIONAL,
+ * fromState [10] BACnetEventState OPTIONAL,
+ * toState [11] BACnetEventState,
+ * eventValues [12] BACnetNotificationParameters OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * GetAlarmSummary-ACK ::= SEQUENCE OF SEQUENCE {
+ * objectIdentifier BACnetObjectIdentifer,
+ * alarmState BACnetEventState,
+ * acknowledgedTransitions BACnetEventTransitionBits
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fGetAlarmSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * GetEnrollmentSummary-Request ::= SEQUENCE {
+ * acknowledgmentFilter [0] ENUMERATED {
+ * all (0),
+ * acked (1),
+ * not-acked (2)
+ * },
+ * enrollmentFilter [1] BACnetRecipientProcess OPTIONAL,
+ * eventStateFilter [2] ENUMERATED {
+ * offnormal (0),
+ * fault (1),
+ * normal (2),
+ * all (3),
+ * active (4)
+ * },
+ * eventTypeFilter [3] BACnetEventType OPTIONAL,
+ * priorityFilter [4] SEQUENCE {
+ * minPriority [0] Unsigned8,
+ * maxPriority [1] Unsigned8
+ * } OPTIONAL,
+ * notificationClassFilter [5] Unsigned OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fGetEnrollmentSummaryRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * GetEnrollmentSummary-ACK ::= SEQUENCE OF SEQUENCE {
+ * objectIdentifier BACnetObjectIdentifer,
+ * eventType BACnetEventType,
+ * eventState BACnetEventState,
+ * priority Unsigned8,
+ * notificationClass Unsigned OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fGetEnrollmentSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * GetEventInformation-Request ::= SEQUENCE {
+ * lastReceivedObjectIdentifier [0] BACnetObjectIdentifer
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fGetEventInformationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * GetEventInformation-ACK ::= SEQUENCE {
+ * listOfEventSummaries [0] listOfEventSummaries,
+ * moreEvents [1] BOOLEAN
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fGetEventInformationACK (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * LifeSafetyOperation-Request ::= SEQUENCE {
+ * requestingProcessIdentifier [0] Unsigned32
+ * requestingSource [1] CharacterString
+ * request [2] BACnetLifeSafetyOperation
+ * objectIdentifier [3] BACnetObjectIdentifier OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);
+
+/**
+ * SubscribeCOV-Request ::= SEQUENCE {
+ * subscriberProcessIdentifier [0] Unsigned32
+ * monitoredObjectIdentifier [1] BACnetObjectIdentifier
+ * issueConfirmedNotifications [2] BOOLEAN OPTIONAL
+ * lifetime [3] Unsigned OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param label
+ * @param src
+ * @return modified offset
+ */
+static guint
+fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * SubscribeCOVProperty-Request ::= SEQUENCE {
+ * subscriberProcessIdentifier [0] Unsigned32
+ * monitoredObjectIdentifier [1] BACnetObjectIdentifier
+ * issueConfirmedNotifications [2] BOOLEAN OPTIONAL
+ * lifetime [3] Unsigned OPTIONAL
+ * monitoredPropertyIdentifier [4] BACnetPropertyReference OPTIONAL
+ * covIncrement [5] Unsigned OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * AtomicReadFile-Request ::= SEQUENCE {
+ * fileIdentifier BACnetObjectIdentifier,
+ * accessMethod CHOICE {
+ * streamAccess [0] SEQUENCE {
+ * fileStartPosition INTEGER,
+ * requestedOctetCount Unsigned
+ * },
+ * recordAccess [1] SEQUENCE {
+ * fileStartRecord INTEGER,
+ * requestedRecordCount Unsigned
+ * }
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAtomicReadFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * AtomicWriteFile-ACK ::= SEQUENCE {
+ * endOfFile BOOLEAN,
+ * accessMethod CHOICE {
+ * streamAccess [0] SEQUENCE {
+ * fileStartPosition INTEGER,
+ * fileData OCTET STRING
+ * },
+ * recordAccess [1] SEQUENCE {
+ * fileStartRecord INTEGER,
+ * returnedRecordCount Unsigned,
+ * fileRecordData SEQUENCE OF OCTET STRING
+ * }
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAtomicReadFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * AtomicWriteFile-Request ::= SEQUENCE {
+ * fileIdentifier BACnetObjectIdentifier,
+ * accessMethod CHOICE {
+ * streamAccess [0] SEQUENCE {
+ * fileStartPosition INTEGER,
+ * fileData OCTET STRING
+ * },
+ * recordAccess [1] SEQUENCE {
+ * fileStartRecord INTEGER,
+ * recordCount Unsigned,
+ * fileRecordData SEQUENCE OF OCTET STRING
+ * }
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * AtomicWriteFile-ACK ::= SEQUENCE {
+ * fileStartPosition [0] INTEGER,
+ * fileStartRecord [1] INTEGER,
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * AddListElement-Request ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * listOfElements [3] ABSTRACT-SYNTAX.&Type
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAddListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * CreateObject-Request ::= SEQUENCE {
+ * objectSpecifier [0] ObjectSpecifier,
+ * listOfInitialValues [1] SEQUENCE OF BACnetPropertyValue OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fCreateObjectRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset);
+
+/**
+ * CreateObject-Request ::= BACnetObjectIdentifier
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * DeleteObject-Request ::= SEQUENCE {
+ * ObjectIdentifier BACnetObjectIdentifer
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fDeleteObjectRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReadProperty-Request ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReadPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReadProperty-ACK ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * propertyValue [3] ABSTRACT-SYNTAX.&Type
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReadPropertyAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReadPropertyConditional-Request ::= SEQUENCE {
+ * objectSelectionCriteria [0] objectSelectionCriteria,
+ * listOfPropertyReferences [1] SEQUENCE OF BACnetPropertyReference OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReadPropertyConditionalRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset);
+
+/**
+ * ReadPropertyConditional-ACK ::= SEQUENCE {
+ * listOfPReadAccessResults SEQUENCE OF ReadAccessResult OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReadPropertyConditionalAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReadPropertyMultiple-Request ::= SEQUENCE {
+ * listOfReadAccessSpecs SEQUENCE OF ReadAccessSpecification
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return offset modified
+ */
+static guint
+fReadPropertyMultipleRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset);
+
+/**
+ * ReadPropertyMultiple-Ack ::= SEQUENCE {
+ * listOfReadAccessResults SEQUENCE OF ReadAccessResult
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return offset modified
+ */
+static guint
+fReadPropertyMultipleAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReadRange-Request ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * range CHOICE {
+ * byPosition [3] SEQUENCE {
+ * referencedIndex Unsigned,
+ * count INTEGER
+ * },
+ * byTime [4] SEQUENCE {
+ * referenceTime BACnetDateTime,
+ * count INTEGER
+ * },
+ * timeRange [5] SEQUENCE {
+ * beginningTime BACnetDateTime,
+ * endingTime BACnetDateTime
+ * },
+ * } OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReadRangeRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReadRange-ACK ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * resultFlags [3] BACnetResultFlags,
+ * itemCount [4] Unsigned,
+ * itemData [5] SEQUENCE OF ABSTRACT-SYNTAX.&Type
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReadRangeAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * RemoveListElement-Request ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * listOfElements [3] ABSTRACT-SYNTAX.&Type
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fRemoveListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * WriteProperty-Request ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * propertyValue [3] ABSTRACT-SYNTAX.&Type
+ * priority [4] Unsigned8 (1..16) OPTIONAL --used only when property is commandable
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fWritePropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * WritePropertyMultiple-Request ::= SEQUENCE {
+ * listOfWriteAccessSpecifications SEQUENCE OF WriteAccessSpecification
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fWritePropertyMultipleRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * DeviceCommunicationControl-Request ::= SEQUENCE {
+ * timeDuration [0] Unsigned16 OPTIONAL,
+ * enable-disable [1] ENUMERATED {
+ * enable (0),
+ * disable (1)
+ * },
+ * password [2] CharacterString (SIZE(1..20)) OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ConfirmedPrivateTransfer-Request ::= SEQUENCE {
+ * vendorID [0] Unsigned,
+ * serviceNumber [1] Unsigned,
+ * serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ConfirmedPrivateTransfer-ACK ::= SEQUENCE {
+ * vendorID [0] Unsigned,
+ * serviceNumber [1] Unsigned,
+ * resultBlock [2] ABSTRACT-SYNTAX.&Type OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ConfirmedTextMessage-Request ::= SEQUENCE {
+ * textMessageSourceDevice [0] BACnetObjectIdentifier,
+ * messageClass [1] CHOICE {
+ * numeric [0] Unsigned,
+ * character [1] CharacterString
+ * } OPTIONAL,
+ * messagePriority [2] ENUMERATED {
+ * normal (0),
+ * urgent (1)
+ * },
+ * message [3] CharacterString
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReinitializeDevice-Request ::= SEQUENCE {
+ * reinitializedStateOfDevice [0] ENUMERATED {
+ * coldstart (0),
+ * warmstart (1),
+ * startbackup (2),
+ * endbackup (3),
+ * startrestore (4),
+ * endrestore (5),
+ * abortrestor (6)
+ * },
+ * password [1] CharacterString (SIZE(1..20)) OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * VTOpen-Request ::= SEQUENCE {
+ * vtClass BACnetVTClass,
+ * localVTSessionIdentifier Unsigned8
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fVtOpenRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * VTOpen-ACK ::= SEQUENCE {
+ * remoteVTSessionIdentifier Unsigned8
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fVtOpenAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * VTClose-Request ::= SEQUENCE {
+ * listOfRemoteVTSessionIdentifiers SEQUENCE OF Unsigned8
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fVtCloseRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * VTData-Request ::= SEQUENCE {
+ * vtSessionIdentifier Unsigned8,
+ * vtNewData OCTET STRING,
+ * vtDataFlag Unsigned (0..1)
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fVtDataRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * VTData-ACK ::= SEQUENCE {
+ * allNewDataAccepted [0] BOOLEAN,
+ * acceptedOctetCount [1] Unsigned OPTIONAL -- present only if allNewDataAccepted = FALSE
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Authenticate-Request ::= SEQUENCE {
+ * pseudoRandomNumber [0] Unsigned32,
+ * excpectedInvokeID [1] Unsigned8 OPTIONAL,
+ * operatorName [2] CharacterString OPTIONAL,
+ * operatorPassword [3] CharacterString (SIZE(1..20)) OPTIONAL,
+ * startEncypheredSession [4] BOOLEAN OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Authenticate-ACK ::= SEQUENCE {
+ * modifiedRandomNumber Unsigned32,
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAuthenticateAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * RequestKey-Request ::= SEQUENCE {
+ * requestingDeviceIdentifier BACnetObjectIdentifier,
+ * requestingDeviceAddress BACnetAddress,
+ * remoteDeviceIdentifier BACnetObjectIdentifier,
+ * remoteDeviceAddress BACnetAddress
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fRequestKeyRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Unconfirmed-Service-Request ::= CHOICE {
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param service_choice
+ * @return modified offset
+ */
+static guint
+fUnconfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice);
+
+/**
+ * UnconfirmedCOVNotification-Request ::= SEQUENCE {
+ * subscriberProcessIdentifier [0] Unsigned32,
+ * initiatingDeviceIdentifier [1] BACnetObjectIdentifer,
+ * monitoredObjectIdentifier [2] BACnetObjectIdentifer,
+ * timeRemaining [3] unsigned,
+ * listOfValues [4] SEQUENCE OF BACnetPropertyValues
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * UnconfirmedEventNotification-Request ::= SEQUENCE {
+ * ProcessIdentifier [0] Unsigned32,
+ * initiatingDeviceIdentifier [1] BACnetObjectIdentifer,
+ * eventObjectIdentifier [2] BACnetObjectIdentifer,
+ * timeStamp [3] BACnetTimeStamp,
+ * notificationClass [4] unsigned,
+ * priority [5] unsigned8,
+ * eventType [6] BACnetEventType,
+ * messageText [7] CharacterString OPTIONAL,
+ * notifyType [8] BACnetNotifyType,
+ * ackRequired [9] BOOLEAN OPTIONAL,
+ * fromState [10] BACnetEventState OPTIONAL,
+ * toState [11] BACnetEventState,
+ * eventValues [12] BACnetNotificationParameters OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * I-Am-Request ::= SEQUENCE {
+ * aAmDeviceIdentifier BACnetObjectIdentifier,
+ * maxAPDULengthAccepted Unsigned,
+ * segmentationSupported BACnetSegmentation,
+ * vendorID Unsigned
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fIAmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+
+/**
+ * I-Have-Request ::= SEQUENCE {
+ * deviceIdentifier BACnetObjectIdentifier,
+ * objectIdentifier BACnetObjectIdentifier,
+ * objectName CharacterString
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fIHaveRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * UnconfirmedPrivateTransfer-Request ::= SEQUENCE {
+ * vendorID [0] Unsigned,
+ * serviceNumber [1] Unsigned,
+ * serviceParameters [2] ABSTRACT-SYNTAX.&Type OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * UnconfirmedTextMessage-Request ::= SEQUENCE {
+ * textMessageSourceDevice [0] BACnetObjectIdentifier,
+ * messageClass [1] CHOICE {
+ * numeric [0] Unsigned,
+ * character [1] CharacterString
+ * } OPTIONAL,
+ * messagePriority [2] ENUMERATED {
+ * normal (0),
+ * urgent (1)
+ * },
+ * message [3] CharacterString
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * TimeSynchronization-Request ::= SEQUENCE {
+ * BACnetDateTime
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * UTCTimeSynchronization-Request ::= SEQUENCE {
+ * BACnetDateTime
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fUTCTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Who-Has-Request ::= SEQUENCE {
+ * limits SEQUENCE {
+ * deviceInstanceRangeLowLimit [0] Unsigned (0..4194303),
+ * deviceInstanceRangeHighLimit [1] Unsigned (0..4194303)
+ * } OPTIONAL,
+ * object CHOICE {
+ * objectIdentifier [2] BACnetObjectIdentifier,
+ * objectName [3] CharacterString
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * Who-Is-Request ::= SEQUENCE {
+ * deviceInstanceRangeLowLimit [0] Unsigned (0..4194303) OPTIONAL, -- must be used as a pair, see 16.9,
+ * deviceInstanceRangeHighLimit [0] Unsigned (0..4194303) OPTIONAL, -- must be used as a pair, see 16.9,
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fWhoIsRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnet-Error ::= CHOICE {
+ * addListElement [8] ChangeList-Error,
+ * removeListElement [9] ChangeList-Error,
+ * writePropertyMultiple [16] WritePropertyMultiple-Error,
+ * confirmedPrivatTransfer [18] ConfirmedPrivateTransfer-Error,
+ * vtClose [22] VTClose-Error,
+ * readRange [26] ObjectAccessService-Error
+ * [default] Error
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param service
+ * @return modified offset
+ */
+static guint
+fBACnetError(tvbuff_t *tvb, proto_tree *tree, guint offset, guint service);
+
+/**
+ * ChangeList-Error ::= SEQUENCE {
+ * errorType [0] Error,
+ * firstFailedElementNumber [1] Unsigned
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * CreateObject-Error ::= SEQUENCE {
+ * errorType [0] Error,
+ * firstFailedElementNumber [1] Unsigned
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fCreateObjectError(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ConfirmedPrivateTransfer-Error ::= SEQUENCE {
+ * errorType [0] Error,
+ * vendorID [1] Unsigned,
+ * serviceNumber [2] Unsigned,
+ * errorParameters [3] ABSTRACT-SYNTAX.&Type OPTIONAL
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fConfirmedPrivateTransferError(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * WritePropertyMultiple-Error ::= SEQUENCE {
+ * errorType [0] Error,
+ * firstFailedWriteAttempt [1] Unsigned
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fWritePropertyMultipleError(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * VTClose-Error ::= SEQUENCE {
+ * errorType [0] Error,
+ * listOfVTSessionIdentifiers [1] SEQUENCE OF Unsigned8 OPTIONAL
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fVTCloseError(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnet Application Types chapter 20.2.1
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param label
+ * @param src
+ * @return modified offset
+ */
+static guint
+fApplicationTypes (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, const value_string *src);
+
+/**
+ * BACnetActionCommand ::= SEQUENCE {
+ * deviceIdentifier [0] BACnetObjectIdentifier OPTIONAL,
+ * objectIdentifier [1] BACnetObjectIdentifier,
+ * propertyIdentifier [2] BACnetPropertyIdentifier,
+ * propertyArrayIndex [3] Unsigned OPTIONAL, -- used only with array datatype
+ * propertyValue [4] ABSTRACT-SYNTAX.&Type,
+ * priority [5] Unsigned (1..16) OPTIONAL, -- used only when property is commandable
+ * postDelay [6] Unsigned OPTIONAL,
+ * quitOnFailure [7] BOOLEAN,
+ * writeSuccessful [8] BOOLEAN
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetActionList ::= SEQUENCE {
+ * action [0] SEQUENCE of BACnetActionCommand
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/** BACnetAddress ::= SEQUENCE {
+ * network-number Unsigned16, -- A value 0 indicates the local network
+ * mac-address OCTET STRING -- A string of length 0 indicates a broadcast
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetAddressBinding ::= SEQUENCE {
+ * deviceObjectID BACnetObjectIdentifier
+ * deviceAddress BacnetAddress
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetCalendaryEntry ::= CHOICE {
+ * date [0] Date,
+ * dateRange [1] BACnetDateRange,
+ * weekNDay [2] BacnetWeekNday
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetClientCOV ::= CHOICE {
+ * real-increment REAL,
+ * default-increment NULL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetCOVSubscription ::= SEQUENCE {
+ * Recipient [0] BACnetRecipientProcess,
+ * MOnitoredPropertyReference [1] BACnetObjectPropertyReference,
+ * IssueConfirmedNotifications [2] BOOLEAN,
+ * TimeRemaining [3] Unsigned,
+ * COVIncrement [4] REAL,
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fCOVSubscription (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetDailySchedule ::= SEQUENCE {
+ * day-schedule [0] SENQUENCE OF BACnetTimeValue
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fDailySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetWeeklySchedule ::= SEQUENCE {
+ * week-schedule SENQUENCE SIZE (7) OF BACnetDailySchedule
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetDateRange ::= SEQUENCE {
+ * StartDate Date,
+ * EndDate Date
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fDateRange (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetDateTime ::= SEQUENCE {
+ * date Date,
+ * time Time
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param label
+ * @return modified offset
+ */
+static guint
+fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);
+
+/**
+ * BACnetDestination ::= SEQUENCE {
+ * validDays BACnetDaysOfWeek,
+ * fromTime Time,
+ * toTime Time,
+ * recipient BACnetRecipient,
+ * processIdentifier Unsigned32,
+ * issueConfirmedNotifications BOOLEAN,
+ * transitions BACnetEventTransitionBits
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetDeviceObjectPropertyReference ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigend OPTIONAL,
+ * deviceIdentifier [3] BACnetObjectIdentifier OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fDeviceObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetDeviceObjectReference ::= SEQUENCE {
+ * deviceIdentifier [0] BACnetObjectIdentifier OPTIONAL,
+ * objectIdentifier [1] BACnetObjectIdentifier
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fDeviceObjectReference (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetEventParameter ::= CHOICE {
+ * change-of-bitstring [0] SEQUENCE {
+ * time-delay [0] Unsigned,
+ * bitmask [1] BIT STRING,
+ * list-of-bitstring-values [2] SEQUENCE OF BIT STRING
+ * },
+ * change-of-state [1] SEQUENCE {
+ * time-delay [0] Unsigned,
+ * list-of-values [1] SEQUENCE OF BACnetPropertyStates
+ * },
+ * change-of-value [2] SEQUENCE {
+ * time-delay [0] Unsigned,
+ * cov-criteria [1] CHOICE {
+ * bitmask [0] BIT STRING,
+ * referenced-property-increment [1] REAL
+ * }
+ * },
+ * command-failure [3] SEQUENCE {
+ * time-delay [0] Unsigned,
+ * feedback-property-reference [1] BACnetDeviceObjectPropertyReference
+ * },
+ * floating-limit [4] SEQUENCE {
+ * time-delay [0] Unsigned,
+ * setpoint-reference [1] BACnetDeviceObjectPropertyReference,
+ * low-diff-limit [2] REAL,
+ * high-diff-limit [3] REAL,
+ * deadband [4] REAL
+ * },
+ * out-of-range [5] SEQUENCE {
+ * time-delay [0] Unsigned,
+ * low-limit [1] REAL,
+ * high-limit [2] REAL,
+ * deadband [3] REAL
+ * },
+ * buffer-ready [7] SEQUENCE {
+ * notification-threshold [0] Unsigned,
+ * previous-notification-count [1] Unsigned32
+ * }
+ * change-of-life-safety [8] SEQUENCE {
+ * time-delay [0] Unsigned,
+ * list-of-life-safety-alarm-values [1] SEQUENCE OF BACnetLifeSafetyState,
+ * list-of-alarm-values [2] SEQUENCE OF BACnetLifeSafetyState,
+ * mode-property-reference [3] BACnetDeviceObjectPropertyReference
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+
+/**
+ * BACnetLogRecord ::= SEQUENCE {
+ * timestamp [0] BACnetDateTime,
+ * logDatum [1] CHOICE {
+ * log-status [0] BACnetLogStatus,
+ * boolean-value [1] BOOLEAN,
+ * real-value [2] REAL,
+ * enum-value [3] ENUMERATED, -- Optionally limited to 32 bits
+ * unsigned-value [4] Unsigned, -- Optionally limited to 32 bits
+ * signed-value [5] INTEGER, -- Optionally limited to 32 bits
+ * bitstring-value [6] BIT STRING,-- Optionally limited to 32 bits
+ * null-value [7] NULL,
+ * failure [8] Error,
+ * time-change [9] REAL,
+ * any-value [10] ABSTRACT-SYNTAX.&Type -- Optional
+ * }
+ * statusFlags [2] BACnetStatusFlags OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetNotificationParameters ::= CHOICE {
+ * change-of-bitstring [0] SEQUENCE {
+ * referenced-bitstring [0] BIT STRING,
+ * status-flags [1] BACnetStatusFlags
+ * },
+ * change-of-state [1] SEQUENCE {
+ * new-state [0] BACnetPropertyStatus,
+ * status-flags [1] BACnetStatusFlags
+ * },
+ * change-of-value [2] SEQUENCE {
+ * new-value [0] CHOICE {
+ * changed-bits [0] BIT STRING,
+ * changed-value [1] REAL
+ * },
+ * status-flags [1] BACnetStatusFlags
+ * },
+ * command-failure [3] SEQUENCE {
+ * command-value [0] ABSTRACT-SYNTAX.&Type, -- depends on ref property
+ * status-flags [1] BACnetStatusFlags
+ * feedback-value [2] ABSTRACT-SYNTAX.&Type -- depends on ref property
+ * },
+ * floating-limit [4] SEQUENCE {
+ * reference-value [0] REAL,
+ * status-flags [1] BACnetStatusFlags
+ * setpoint-value [2] REAL,
+ * error-limit [3] REAL
+ * },
+ * out-of-range [5] SEQUENCE {
+ * exceeding-value [0] REAL,
+ * status-flags [1] BACnetStatusFlags
+ * deadband [2] REAL,
+ * exceeded-limit [0] REAL
+ * },
+ * complex-event-type [6] SEQUENCE OF BACnetPropertyValue,
+ * buffer-ready [7] SEQUENCE {
+ * buffer-device [0] BACnetObjectIdentifier,
+ * buffer-object [1] BACnetObjectIdentifier
+ * previous-notification [2] BACnetDateTime,
+ * current-notification [3] BACnetDateTime
+ * },
+ * change-of-life-safety [8] SEQUENCE {
+ * new-state [0] BACnetLifeSafetyState,
+ * new-mode [1] BACnetLifeSafetyState
+ * status-flags [2] BACnetStatusFlags,
+ * operation-expected [3] BACnetLifeSafetyOperation
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetObjectPropertyReference ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetObjectPropertyValue ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * propertyIdentifier [1] BACnetPropertyIdentifier,
+ * propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
+ * -- if omitted with an array the entire array is referenced
+ * value [3] ABSTRACT-SYNTAX.&Type, --any datatype appropriate for the specified property
+ * priority [4] Unsigned (1..16) OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetPriorityArray ::= SEQUENCE SIZE (16) OF BACnetPriorityValue
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fPriorityArray (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetPropertyReference ::= SEQUENCE {
+ * propertyIdentifier [0] BACnetPropertyIdentifier,
+ * propertyArrayIndex [1] Unsigned OPTIONAL, -- used only with array datatype
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetPropertyValue ::= SEQUENCE {
+ * PropertyIdentifier [0] BACnetPropertyIdentifier,
+ * propertyArrayIndex [1] Unsigned OPTIONAL, -- used only with array datatypes
+ * -- if omitted with an array the entire array is referenced
+ * value [2] ABSTRACT-SYNTAX.&Type, -- any datatype appropriate for the specified property
+ * priority [3] Unsigned (1..16) OPTIONAL -- used only when property is commandable
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnet Application PDUs chapter 21
+ * BACnetRecipient::= CHOICE {
+ * device [0] BACnetObjectIdentifier
+ * address [1] BACnetAddress
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnet Application PDUs chapter 21
+ * BACnetRecipientProcess::= SEQUENCE {
+ * recipient [0] BACnetRecipient
+ * processID [1] Unsigned32
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetSessionKey ::= SEQUENCE {
+ * sessionKey OCTET STRING (SIZE(8)), -- 56 bits for key, 8 bits for checksum
+ * peerAddress BACnetAddress
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ * @todo check if checksum is displayed correctly
+ */
+static guint
+fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetSetpointReference ::= SEQUENCE {
+ * sessionKey [0] BACnetObjectPropertyReference OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetSpecialEvent ::= SEQUENCE {
+ * period CHOICE {
+ * calendarEntry [0] BACnetCalendarEntry,
+ * calendarRefernce [1] BACnetObjectIdentifier
+ * },
+ * listOfTimeValues [2] SEQUENCE OF BACnetTimeValue,
+ * eventPriority [3] Unsigned (1..16)
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fSpecialEvent (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetTimeStamp ::= CHOICE {
+ * time [0] Time,
+ * sequenceNumber [1] Unsigned (0..65535),
+ * dateTime [2] BACnetDateTime
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetTimeValue ::= SEQUENCE {
+ * time Time,
+ * value ABSTRACT-SYNTAX.&Type -- any primitive datatype, complex types cannot be decoded
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetVTSession ::= SEQUENCE {
+ * local-vtSessionID Unsigned8,
+ * remote-vtSessionID Unsigned8,
+ * remote-vtAddress BACnetAddress
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fVTSession (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnetWeekNDay ::= OCTET STRING (SIZE (3))
+ * -- first octet month (1..12) January = 1, X'FF' = any month
+ * -- second octet weekOfMonth where: 1 = days numbered 1-7
+ * -- 2 = days numbered 8-14
+ * -- 3 = days numbered 15-21
+ * -- 4 = days numbered 22-28
+ * -- 5 = days numbered 29-31
+ * -- 6 = last 7 days of this month
+ * -- X’FF’ = any week of this month
+ * -- third octet dayOfWeek (1..7) where 1 = Monday
+ * -- 7 = Sunday
+ * -- X'FF' = any day of week
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReadAccessResult ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * listOfResults [1] SEQUENCE OF SEQUENCE {
+ * propertyIdentifier [2] BACnetPropertyIdentifier,
+ * propertyArrayIndex [3] Unsigned OPTIONAL, -- used only with array datatype if omitted with an array the entire array is referenced
+ * readResult CHOICE {
+ * propertyValue [4] ABSTRACT-SYNTAX.&Type,
+ * propertyAccessError [5] Error
+ * }
+ * } OPTIONAL
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * ReadAccessSpecification ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * listOfPropertyReferences [1] SEQUENCE OF BACnetPropertyReference
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fReadAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset);
+
+/**
+ * WriteAccessSpecification ::= SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * listOfProperty [1] SEQUENCE OF BACnetPropertyValue
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset);
+
+
+/********************************************************* Helper functions *******************************************/
+
+/**
+ * extracts the tag number from the tag header.
+ * @param tvb "TestyVirtualBuffer"
+ * @param offset in actual tvb
+ * @return Tag Number corresponding to BACnet 20.2.1.2 Tag Number
+ */
+static guint
+fTagNo (tvbuff_t *tvb, guint offset);
+
+/**
+ * splits Tag Header coresponding to 20.2.1 General Rules For BACnet Tags
+ * @param tvb = "TestyVirtualBuffer"
+ * @param offset = offset in actual tvb
+ * @return tag_no BACnet 20.2.1.2 Tag Number
+ * @return class_tag BACnet 20.2.1.1 Class
+ * @return lvt BACnet 20.2.1.3 Length/Value/Type
+ * @return offs = length of this header
+ */
+
+static guint
+fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* class_tag, guint32 *lvt);
+
+
+/**
+ * adds processID with max 32Bit unsigned Integer Value to tree
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * adds timeSpan with max 32Bit unsigned Integer Value to tree
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label);
+
+/**
+ * BACnet Application PDUs chapter 21
+ * BACnetPropertyIdentifier::= ENUMERATED {
+ * @see bacapp_property_identifier
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @param tt returnvalue of this item
+ * @return modified offset
+ */
+static guint
+fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset, proto_item **tt);
+
+/**
+ * listOfEventSummaries ::= SEQUENCE OF SEQUENCE {
+ * objectIdentifier [0] BACnetObjectIdentifier,
+ * eventState [1] BACnetEventState,
+ * acknowledgedTransitions [2] BACnetEventTransitionBits,
+ * eventTimeStamps [3] SEQURNCE SIZE (3) OF BACnetTimeStamps,
+ * notifyType [4] BACnetNotifyType,
+ * eventEnable [5] BACnetEventTransitionBits,
+ * eventPriorities [6] SEQUENCE SIZE (3) OF Unsigned
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+flistOfEventSummaries (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * SelectionCriteria ::= SEQUENCE {
+ * propertyIdentifier [0] BACnetPropertyIdentifier,
+ * propertyArrayIndex [1] Unsigned OPTIONAL, -- used only with array datatype
+ * relationSpecifier [2] ENUMERATED { bacapp_relationSpecifier },
+ * comparisonValue [3] ABSTRACT-SYNTAX.&Type
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fSelectionCriteria (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * objectSelectionCriteria ::= SEQUENCE {
+ * selectionLogic [0] ENUMERATED { bacapp_selectionLogic },
+ * listOfSelectionCriteria [1] SelectionCriteria
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset);
+
+/**
+ * ObjectSpecifier ::= CHOICE {
+ * objectType [0] BACnetObjectType,
+ * objectIdentifier [1] BACnetObjectIdentifier
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fObjectSpecifier (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * BACnet-Error ::= SEQUENCE {
+ * error-class ENUMERATED {},
+ * error-code ENUMERATED {}
+ * }
+ * }
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ */
+static guint
+fError(tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * realizes some ABSTRACT-SYNTAX.&Type
+ * @param tvb
+ * @param tree
+ * @param offset
+ * @return modified offset
+ * @todo beautify this ugly construct
+ */
+static guint
+fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset);
+
+/**
+ * register_bacapp
+ */
+void
+proto_register_bacapp(void);
+
+/**
+ * proto_reg_handoff_bacapp
+ */
+void
+proto_reg_handoff_bacapp(void);
+
+/**
+ * converts XXX coded strings to UTF-8 if iconv is allowed
+ * else 'in' is copied to 'out'
+ * @param in -- pointer to string
+ * @param inbytesleft
+ * @param out -- pointer to string
+ * @param outbytesleft
+ * @param fromcoding
+ * @return count of modified characters of returned string, -1 for errors
+ */
+guint32
+fConvertXXXtoUTF8(guint8 *in, guint32 *inbytesleft,guint8 *out, guint32 *outbytesleft, guint8 *fromcoding);
+
+#endif /* __BACAPP_H__ */
+
+