Ethereal-dev: [Ethereal-dev] Patch to packet-bacapp.c
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Herbert Lischka <herbert@xxxxxxxxxxxxxxxxx>
Date: Wed, 16 Feb 2005 18:13:18 +0100
Hi list,this patch implements some (not all) tags according to bacnet application handbook
please check in thanks Herbert
Index: epan/dissectors/packet-bacapp.c =================================================================== --- epan/dissectors/packet-bacapp.c (revision 13415) +++ epan/dissectors/packet-bacapp.c (working copy) @@ -2,6 +2,8 @@ * Routines for BACnet (APDU) dissection * Copyright 2001, Hartmut Mueller <hartmut@xxxxxxxxxxxx>, FH Dortmund * + * modified 2004, Herbert Lischka <lischka@xxxxxxxxxxxxxxxx>, Berlin + * * $Id$ * * Ethereal - Network traffic analyzer @@ -37,81 +39,3538 @@ #include <epan/packet.h> -static const char* -bacapp_type_name (guint8 bacapp_type){ - static const char *type_names[] = { - "Confirmed-Request-PDU", - "Unconfirmed-Request-PDU", - "SimpleACK-PDU", - "ComplexACK-PDU", - "SegmentACK-PDU", - "Error-PDU", - "Reject-PDU", - "Abort-PDU" - }; - return (bacapp_type > 7)? "unknown PDU" : type_names[bacapp_type]; -} +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +static const value_string bacapp_type_name[] = { + {0, "Conf-Request "}, + {1, "Unconf-Request "}, + {2, "SimpleACK-PDU "}, + {3, "ComplexACK-PDU "}, + {4, "SegmentACK-PDU "}, + {5, "#### Error-PDU #### "}, + {6, "---- Reject-PDU ---- "}, + {7, "==== Abort-PDU ==== "}, + {0, NULL } +}; + +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 bacapp_tag_class = { + "Context Specific Tag", + "Application Tag" +}; + +static const value_string +bacapp_max_segments_accepted [] = { + {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 +bacapp_max_APDU_length_accepted [] = { + {0, "Up to MinimumMessageSize (50 octets)"}, + {1, "Up to 128 octets"}, + {2, "Up to 206 octets (fits in a LonTalk frame)"}, + {3, "Up to 480 octets (fits in an ARCNET frame)"}, + {4, "Up to 1024 octets"}, + {5, "Up to 1476 octets"}, + {6, "reserved by ASHRAE"}, + {7, "reserved by ASHRAE"}, + {8, "reserved by ASHRAE"}, + {9, "reserved by ASHRAE"}, + {10, "reserved by ASHRAE"}, + {11, "reserved by ASHRAE"}, + {12, "reserved by ASHRAE"}, + {13, "reserved by ASHRAE"}, + {14, "reserved by ASHRAE"}, + {15, "reserved by ASHRAE"}, + {0, NULL} +}; + +static const value_string +bacapp_reject_reason [] = { + {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 +bacapp_tag_number [] = { + {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 +bacapp_abort_reason [] = { + {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 +bacapp_confirmed_service_choice [] = { + {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 +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 +bacapp_object_type [] = { + {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 +bacapp_error_code [] = { + {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 +bacapp_property_identifier [] = { + {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-svhedule"}, + {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 +bacapp_character_set [] = { + {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 +bacapp_status_flags [] = { + {0, "in-alarm"}, + {1, "fault"}, + {2, "overridden"}, + {3, "out-of-service"}, + {0, NULL} +}; + +static const value_string +bacapp_messagePriority [] = { + {0, "normal"}, + {1, "urgent"}, + {0, NULL} +}; + +static const value_string +bacapp_AcknowledgementFilter [] = { + {0, "and"}, + {1, "or"}, + {2, "all"}, + {0, NULL} +}; + +static const value_string +bacapp_resultFlags [] = { + {0, "firstitem"}, + {1, "lastitem"}, + {2, "moreitems"}, + {0, NULL} +}; + +static const value_string +bacapp_relationSpecifier [] = { + {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 +bacapp_selectionLogic [] = { + {0, "normal"}, + {1, "urgent"}, + {0, NULL} +}; + +static const value_string +bacapp_eventStateFilter [] = { + {0, "offnormal"}, + {1, "fault"}, + {2, "normal"}, + {3, "all"}, + {4, "active"}, + {0, NULL} +}; + +static const value_string +bacapp_EventTransitionBits [] = { + {0, "to-offnormal"}, + {1, "to-fault"}, + {2, "to-normal"}, + {0, NULL} +}; + +static const value_string +bacapp_segmentation [] = { + {0, "segmented-both"}, + {1, "segmented-transmit"}, + {2, "segmented-receive"}, + {3, "no-segmentation"}, + {0, NULL} +}; + +static const value_string +bacapp_deviceStatus [] = { + {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 +bacapp_statusFlags [] = { + {0, "in-alarm"}, + {1, "fault"}, + {2, "overridden"}, + {3, "out-of-service"}, + {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, "unspecified" }, + {0, NULL } +}; + +static const value_string +days [] = { + {1, "Monday" }, + {2, "Tuesday" }, + {3, "Wednesday" }, + {4, "Thursday" }, + {5, "Friday" }, + {6, "Saturday" }, + {7, "Sonday" }, + {255, "unspecified" }, + {0, NULL }, +}; + +static const value_string +bacapp_errorClass [] = { + {0, "device" }, + {1, "object" }, + {2, "property" }, + {3, "resources" }, + {4, "security" }, + {5, "services" }, + {6, "vt" }, + {0, NULL }, +}; + +static const value_string +bacapp_EventType [] = { + {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 +bacapp_EventState [] = { + {0, "normal" }, + {1, "fault" }, + {2, "offnormal" }, + {3, "high-limit" }, + {4, "low-limit" }, + {5, "life-safety-alarm" }, + {0, NULL }, +}; + +static const value_string +bacapp_NotifyType [] = { + {0, "alarm" }, + {1, "event" }, + {2, "ack-notification" }, + {0, NULL }, +}; + +static const value_string +bacapp_servicesSupported [] = { + {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 +bacapp_PropertyStates [] = { + {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 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_sequence_number = -1; +static int hf_bacapp_window_size = -1; +static int hf_bacapp_service = -1; +static int hf_bacapp_NAK = -1; +static int hf_bacapp_SRV = -1; +static int hf_bacapp_reject_reason = -1; +static int hf_bacapp_abort_reason = -1; +static int hf_bacapp_tag_number = -1; +static int hf_bacapp_tag_class = -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_tag_initiatingObjectId = -1; */ +static int hf_bacapp_vpart = -1; +/* +static int hf_bacapp_tag_null = -1; +static int hf_bacapp_tag_boolean = -1; +static int hf_bacapp_tag_uint8 = -1; +static int hf_bacapp_tag_uint16 = -1; +static int hf_bacapp_tag_uint32 = -1; +static int hf_bacapp_tag_uint64 = -1; +static int hf_bacapp_tag_sint8 = -1; +static int hf_bacapp_tag_sint16 = -1; +static int hf_bacapp_tag_sint32 = -1; +static int hf_bacapp_tag_sint64 = -1; +static int hf_bacapp_tag_real = -1; +static int hf_bacapp_tag_double = -1; +static int hf_bacapp_initiatingObject = -1; +static int hf_bacapp_monitoredObject = -1; +static int hf_bacapp_tag_timeRemaining = -1; +static int hf_bacapp_tag_string = -1; +static int hf_bacapp_tag_bytes = -1; +static int hf_bacapp_tag_character_set = -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 dissector_handle_t data_handle; -static void -dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +static gint32 propertyIdentifier = -1; + +static guint8 bacapp_flags = 0; +static guint8 bacapp_seq = 0; + + +int +fTagHeader (tvbuff_t *tvb, guint *offset, guint8 *tag_no, guint8* class_tag, guint64 *lvt) { - proto_item *ti; + int tmp, retVal = 0; + + tmp = tvb_get_guint8(tvb, *offset); + *class_tag = tmp & 0x08; + *lvt = tmp & 0x07; + *tag_no = tmp >> 4; + if (*tag_no == 15) { /* B'1111' because of extended tagnumber */ + *tag_no = tvb_get_guint8(tvb, (*offset)+1); + retVal++; + } + if (*lvt == 5) { /* length is more than 4 Bytes */ + *lvt = tvb_get_guint8(tvb, (*offset)+retVal+1); + retVal++; + if (*lvt == 254) { /* length is more than 253 Bytes */ + *lvt = tvb_get_guint8(tvb, (*offset)+retVal+1); + retVal++; + *lvt = (*lvt << 8) + tvb_get_guint8(tvb, (*offset)+retVal+1); + retVal++; + } + } + + return retVal; +} + +#define LABEL(lbl) (lbl==NULL ? (guint8 *) " Value: " : lbl) + + +void +fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt) +{ + guint8 tmp, i; + long val = 0; + + (*offset)++; + for (i = 0; i < min((guint8) lvt,8); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + proto_tree_add_text(tree, tvb, *offset, min((guint8) lvt,8), "%s%ld", LABEL(label), val); + (*offset)+=min((guint8) lvt,8); +} + +void +fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt) +{ + guint8 tmp, i; + long val = 0; + + (*offset)++; + for (i = 0; i < min((guint8) lvt,8); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + proto_tree_add_text(tree, tvb, *offset, min((guint8) lvt,8), "%s%ld", LABEL(label), val); + (*offset)+=min((guint8) lvt,8); +} + +void +fDateTag (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt) +{ + guint32 year, month, day, weekday; + + (*offset)++; + year = tvb_get_guint8(tvb, (*offset)) + 1900; + month = tvb_get_guint8(tvb, (*offset)+1); + day = tvb_get_guint8(tvb, (*offset)+2); + weekday = tvb_get_guint8(tvb, (*offset)+3); + if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255)) + proto_tree_add_text(tree, tvb, *offset, (guint8) lvt, "%sany", LABEL(label)); + else + proto_tree_add_text(tree, tvb, *offset, (guint8) lvt, "%s%s %d, %d, (Day of Week = %s)", LABEL(label), match_strval(month, months), day, year, match_strval(weekday, days)); + (*offset)+=(guint8) lvt; +} + +void +fTimeTag (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt) +{ + guint32 year, month, day, weekday; + + (*offset)++; + year = tvb_get_guint8(tvb, (*offset)); + month = tvb_get_guint8(tvb, (*offset)+1); + day = tvb_get_guint8(tvb, (*offset)+2); + weekday = tvb_get_guint8(tvb, (*offset)+3); + if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255)) + proto_tree_add_text(tree, tvb, *offset, (guint8) lvt, "%sany", LABEL(label)); + else + proto_tree_add_text(tree, tvb, *offset, (guint8) lvt, "%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); + (*offset)+=(guint8) lvt; +} + +void +fOctetString (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, guint64 lvt) +{ + guint8 *str_val, len; + + if ((lvt == 0) || (lvt > tvb->length)) + lvt = tvb->length - *offset; + + proto_tree_add_text(tree, tvb, *offset, (int)lvt, "[displayed OctetString with %ld Bytes:] %s", (long)lvt, LABEL(label)); + + do { + len = (guint8) 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->reported_length) + proto_tree_add_text(tree, tvb, *offset-1, 1, "[Frame is %d Bytes shorter than expected]", tvb->reported_length - tvb->length); + +} + +void +fBACnetAddress (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + fUnsignedTag (tvb, tree, offset, "network-number", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (lvt == 0) + proto_tree_add_text(tree, tvb, *offset-1, 1, "mac-address: broadcast"); + else + fOctetString (tvb, tree, offset, "mac-address: ", lvt); +} + +void +fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label) +{ + guint8 offs, tag_no, class_tag; + guint32 tmp, val = 0, type; + guint64 lvt; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + (*offset)+= offs + 1; + + val = tvb_get_guint8(tvb, (*offset)); + tmp = tvb_get_guint8(tvb, (*offset)+1); + type = (val << 2) + (tmp >> 6); + val = ((tmp & 0x03) << 16) + (tvb_get_guint8(tvb, (*offset)+2) << 8) + tvb_get_guint8(tvb, (*offset)+3); + proto_tree_add_text(tree, tvb, *offset, 4, + "%s%s, instance number %d", LABEL(label), val_to_str(type, bacapp_object_type, "(%d) reserved for ASHREA"), val); + (*offset)+=4; +} + +void +fRecipient (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* device */ + fObjectIdentifier (tvb, tree, offset, "device: "); + break; + case 1: /* address */ + fBACnetAddress (tvb, tree, offset); + break; + default: + return; + break; + } + fRecipient (tvb, pinfo, tree, offset); +} + + +void +fRecipientProcess (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* recipient */ + fRecipient (tvb, pinfo, tree, offset); + break; + case 1: /* processId */ + fUnsignedTag (tvb, tree, offset, "processId: ", lvt); + break; + default: + return; + break; + } + fRecipientProcess (tvb, pinfo, tree, offset); +} + +void +fBACnetAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + fObjectIdentifier (tvb, tree, offset, "deviceObjectId: "); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fBACnetAddress (tvb, tree, offset); +} + +int +fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label) +{ + guint8 offs, tag_no, class_tag, tmp, i; + guint64 lvt; + guint val = 0; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + (*offset) += offs + 1; + + for (i = 0; i < min((guint8) lvt,4); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + proto_tree_add_text(tree, tvb, *offset, min((guint8) lvt,4), + "%s%s", LABEL(label),val_to_str(val, bacapp_property_identifier, "(%d) reserved for ASHREA")); + (*offset)+=min((guint8) lvt,4); + return val; +} + +void +fApplicationTags (tvbuff_t *tvb, proto_tree *tree, guint *offset, guint8 *label, const value_string + *src) +{ + guint8 offs, tag_no, class_tag, tmp, i, j, unused; + guint64 val = 0, lvt; + gfloat f_val = 0.0; + gdouble d_val = 0.0; + guint8 *str_val; + guint8 bf_arr[256]; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + (*offset) += offs; /* set offset according to enhancements.... */ + + switch (tag_no) { + case 0: /* NULL */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "%sNULL", LABEL(label)); + break; + case 1: /* BOOLEAN */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "%s%s", LABEL(label), lvt == 0 ? "FALSE" : "TRUE"); + break; + case 2: /* Unsigned Integer */ + fUnsignedTag (tvb, tree, offset, label, lvt); + break; + case 3: /* Signed Integer */ + fSignedTag (tvb, tree, offset, label, lvt); + break; + case 4: /* Real */ + (*offset)++; + f_val = tvb_get_ntohieee_float(tvb, *offset); + proto_tree_add_text(tree, tvb, *offset, 4, "%s%f", LABEL(label), f_val); + (*offset)+=4; + break; + case 5: /* Double */ + (*offset)++; + d_val = tvb_get_ntohieee_double(tvb, *offset); + proto_tree_add_text(tree, tvb, *offset, 8, "%s%lf", LABEL(label), d_val); + (*offset)+=8; + break; + case 6: /* Octet String */ + (*offset)++; + proto_tree_add_text(tree, tvb, *offset-offs-1, offs+1, "%s (%d Characters)", LABEL(label), (int)lvt); + fOctetString (tvb, tree, offset, label, lvt); + break; + case 7: /* Character String */ + (*offset)++; + tmp = tvb_get_guint8(tvb, *offset); + if (tmp == 3) { + proto_tree_add_text (tree, tvb, *offset, 4, " String Character Set: %s", val_to_str((guint) tmp, bacapp_character_set, "Reserved by ASHRAE")); + (*offset)+=4; + lvt-=4; + } + if (tmp == 4) { + proto_tree_add_text (tree, tvb, *offset, 2, " String Character Set: %s", val_to_str((guint) tmp, bacapp_character_set, "Reserved by ASHRAE")); + (*offset)+=2; + lvt-=2; + } + if ((tmp != 3) && (tmp != 4)) { + proto_tree_add_text (tree, tvb, *offset, 1, " String Character Set: %s", val_to_str((guint) tmp, bacapp_character_set, "Reserved by ASHRAE")); + (*offset)++; + lvt--; + } + do { + guint8 l = (guint8) min(lvt, 255); + str_val = tvb_get_string(tvb, *offset, l); + /* this decoding is not correct for multi-byte characters, Lka */ + proto_tree_add_text(tree, tvb, *offset, l, "%s'%s'", LABEL(label), str_val); + g_free(str_val); + lvt -= l; + (*offset) += l; + } while (lvt > 0); + break; + case 8: /* Bit String */ + (*offset)++; + 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)+(guint8)lvt-1); /* jetzt das letzte 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, (guint8)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)+=(guint8)lvt; + break; + case 9: /* Enumerated */ + (*offset)++; + for (i = 0; i < min((guint8) lvt,8); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + if (src != NULL) + proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "%s%s", LABEL(label), val_to_str((guint) val, src, "Reserved by ASHRAE")); + else + proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "%s%ld", LABEL(label), (long)val); + + (*offset)+=(guint8)lvt; + break; + case 10: /* Date */ + fDateTag (tvb, tree, offset, label, lvt); + break; + case 11: /* Time */ + fTimeTag (tvb, tree, offset, label, lvt); + break; + case 12: /* BACnetObjectIdentifier */ + fObjectIdentifier (tvb, tree, offset, LABEL(label)); + break; + case 13: /* reserved for ASHRAE */ + case 14: + case 15: + (*offset)++; + proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "%s'reserved for ASHRAE'", LABEL(label)); + (*offset)+=(guint8)lvt; + break; + } +} + +void +fPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + static int awaitingClosingTag = 0; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + if (((lvt == 7) && (offs == 0)) && !awaitingClosingTag) { /* closing Tag */ + return; /* but not for me */ + } + + if (class_tag) { + switch (tag_no) { + case 0: /* PropertyIdentifier */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, " property Identifier: "); + break; + case 1: /* propertyArrayIndex */ + fPropertyIdentifier (tvb, tree, offset, "propertyArrayIndex: "); + break; + case 2: /* Value */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + awaitingClosingTag = 1; + if (propertyIdentifier == 111) { /* status-flags */ + fApplicationTags (tvb, tree, offset, " propertyValue: ", bacapp_statusFlags); + } else { + fApplicationTags (tvb, tree, offset, NULL, NULL); + } + } + if (((lvt == 7) && (offs == 0))) /* closing Tag */ + awaitingClosingTag = 0; /* ignore corresponding closing Tag, just throw ist away */ + break; + case 3: /* Priority */ + (*offset) += offs; /* set offset according to enhancements.... */ + fSignedTag (tvb, tree, offset, " Priority: ", lvt); + break; + default: + break; + } + } else { + switch (propertyIdentifier) + { + case 97: /* Protocol-Services-Supported */ + fApplicationTags (tvb, tree, offset, " propertyValue: ", bacapp_servicesSupported); + break; + case 111: /* Status-Flags */ + fApplicationTags (tvb, tree, offset, " propertyValue: ", bacapp_statusFlags); + break; + case 76: /* object-list */ + fApplicationTags (tvb, tree, offset, " propertyValue: ", NULL); + break; + default: + fApplicationTags (tvb, tree, offset, " propertyValue: ", NULL); + break; + } + } + fPropertyValue (tvb, pinfo, tree, offset); +} + +void +fSubscribeCOV (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tmp, tag_no, class_tag, i; + guint64 lvt; + guint32 val = 0; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* ProcessId */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + for (i = 0; i < (guint8) min(lvt, 2); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + + proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, *offset, (guint8)lvt, val); + (*offset)+=(guint8)lvt; + break; + case 1: /* monitored ObjectId */ + fObjectIdentifier (tvb, tree, offset, "monitored ObjectId: "); + break; + case 2: /* issueConfirmedNotifications */ + fApplicationTags (tvb, tree, offset, "issueConfirmedNotifications: ", NULL); + break; + case 3: /* life time */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + for (i = 0; i < (guint8) min(lvt, 4); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "life time (hh.mm.ss): %d.%02d.%02d%s", (int)(val / 3600), (int)((val % 3600) / 60), (int)(val % 60), val == 0 ? " (indefinite)" : ""); + (*offset)+=(guint8)lvt; + return; + break; + default: + return; + break; + } + fSubscribeCOV (tvb, pinfo, tree, offset); +} + +void +fWhoHas (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* deviceInstanceLowLimit */ + fUnsignedTag (tvb, tree, offset, "deviceInstanceLowLimit: ", lvt); + break; + case 1: /* deviceInstanceHighLimit */ + fUnsignedTag (tvb, tree, offset, "deviceInstanceHighLimit: ", lvt); + break; + case 2: /* BACnetObjectId */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectId: "); + break; + case 3: /* messageText */ + fApplicationTags (tvb, tree, offset, "ObjectName: ", NULL); + break; + default: + return; + } + fWhoHas (tvb, pinfo, tree, offset); +} + +void +fUTCTimeSynchronization (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + fDateTag (tvb, tree, offset, "Date: ", lvt); + fTimeTag (tvb, tree, offset, "UTC-Time: ", lvt); +} + +void +fTimeSynchronization (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + fDateTag (tvb, tree, offset, "Date: ", lvt); + fTimeTag (tvb, tree, offset, "Time: ", lvt); +} + +void +fTextMessage (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* textMessageSourceDevice */ + fObjectIdentifier (tvb, tree, offset, "TextMessageSourceDevice: "); + break; + case 1: /* messageClass */ + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + switch (tag_no) { + case 0: /* numeric */ + fUnsignedTag (tvb, tree, offset, " messageClass: ", lvt); + break; + case 1: /* character */ + fApplicationTags (tvb, tree, offset, "messageClass: ", NULL); + break; + } + break; + case 2: /* messagePriority */ + fApplicationTags (tvb, tree, offset, "ObjectName: ", bacapp_messagePriority); + break; + case 3: /* message */ + fApplicationTags (tvb, tree, offset, "message: ", NULL); + break; + } + fTextMessage (tvb, pinfo, tree, offset); +} + +void +fPrivateTransfer (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* vendorID */ + fUnsignedTag (tvb, tree, offset, " vendorID: ", lvt); + break; + case 1: /* serviceNumber */ + fUnsignedTag (tvb, tree, offset, " serviceNumber: ", lvt); + break; + case 2: /*serviceParameters */ + if (!((lvt == 7) && (offs == 0))) { /* not closing Tag */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + proto_tree_add_text(tree, tvb, *offset, max(offs,1), "list of Values {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } else { + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + } +} + +void +fNotificationParameters (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* change-of-bitstring */ + fApplicationTags (tvb, tree, offset, "referenced-bitstring: ", NULL); + fApplicationTags (tvb, tree, offset, "status-flags: ", bacapp_statusFlags); + break; + case 1: /* change-of-state */ + fApplicationTags (tvb, tree, offset, "new-state: ", bacapp_PropertyStates); + fApplicationTags (tvb, tree, offset, "status-flags: ", bacapp_statusFlags); + break; + default: + return; + } + fNotificationParameters (tvb, pinfo, tree, offset); +} + +void +fEventNotification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tmp, tag_no, class_tag, i; + guint64 lvt; + guint32 val = 0; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* ProcessId */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + for (i = 0; i < min((guint8) lvt, 2); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + + proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, *offset, (guint8)lvt, val); + (*offset)+=(guint8)lvt; + break; + case 1: /* initiating ObjectId */ + fObjectIdentifier (tvb, tree, offset, "initiating DeviceId: "); + break; + case 2: /* event ObjectId */ + fObjectIdentifier (tvb, tree, offset, "event ObjectId: "); + break; + case 3: /* time stamp */ + fApplicationTags (tvb, tree, offset, "Time Stamp: ", NULL); + break; + case 4: /* notificationClass */ + fApplicationTags (tvb, tree, offset, "Notification Class: ", NULL); + break; + case 5: /* Priority */ + fApplicationTags (tvb, tree, offset, "Priority: ", NULL); + break; + case 6: /* EventType */ + fApplicationTags (tvb, tree, offset, "EventType: ", bacapp_EventType); + break; + case 7: /* messageText */ + fApplicationTags (tvb, tree, offset, "messageText: ", NULL); + break; + case 8: /* NotifyType */ + fApplicationTags (tvb, tree, offset, "NotifyType: ", bacapp_NotifyType); + break; + case 9: /* ackRequired */ + fApplicationTags (tvb, tree, offset, "ackRequired: ", NULL); + break; + case 10: /* fromState */ + fApplicationTags (tvb, tree, offset, "fromState: ", bacapp_EventState); + break; + case 11: /* toState */ + fApplicationTags (tvb, tree, offset, "toState: ", bacapp_EventState); + break; + case 12: /* NotificationParameters */ + fNotificationParameters (tvb, pinfo, tree, offset); + break; + default: + return; + break; + } + fEventNotification (tvb, pinfo, tree, offset); +} + +void +fCOVNotification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tmp, tag_no, class_tag, i; + guint64 lvt; + guint32 val = 0; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* ProcessId */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + for (i = 0; i < min((guint8) lvt, 2); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + + proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, *offset, (guint8)lvt, val); + (*offset)+=(guint8)lvt; + break; + case 1: /* initiating ObjectId */ + fObjectIdentifier (tvb, tree, offset, "initiating ObjectId: "); + break; + case 2: /* monitored ObjectId */ + fObjectIdentifier (tvb, tree, offset, "monitored ObjectId: "); + break; + case 3: /* time remaining */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + for (i = 0; i < min((guint8) lvt, 4); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "time remaining (hh.mm.ss): %d.%02d.%02d%s", (int)(val / 3600), (int)((val % 3600) / 60), (int)(val % 60), val == 0 ? " (indefinite)" : ""); + (*offset)+=(guint8)lvt; + break; + case 4: /* List of Values */ + if (!((lvt == 7) && (offs == 0))) { /* not closing Tag */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + proto_tree_add_text(tree, tvb, *offset, max(offs,1), "list of Values {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } else { + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + default: + return; + break; + } + fCOVNotification (tvb, pinfo, tree, offset); +} + +void +fAckAlarm (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tmp, tag_no, class_tag, i; + guint64 lvt; + guint32 val = 0; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* acknowledgingProcessId */ + fUnsignedTag (tvb, tree, offset, "initiating ObjectId: ", lvt); + break; + case 1: /* initiating ObjectId */ + fObjectIdentifier (tvb, tree, offset, "initiating ObjectId: "); + break; + case 2: /* monitored ObjectId */ + fObjectIdentifier (tvb, tree, offset, "monitored ObjectId: "); + break; + case 3: /* time remaining */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + for (i = 0; i < min((guint8) lvt, 4); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + proto_tree_add_text(tree, tvb, *offset, (guint8)lvt, "time remaining (hh.mm.ss): %d.%02d.%02d%s", (int)(val / 3600), (int)((val % 3600) / 60), (int)(val % 60), val == 0 ? " (indefinite)" : ""); + (*offset)+=(guint8)lvt; + break; + case 4: /* List of Values */ + if (!((lvt == 7) && (offs == 0))) { /* not closing Tag */ + (*offset) += offs + 1; /* set offset according to enhancements.... */ + proto_tree_add_text(tree, tvb, *offset, max(offs,1), "list of Values {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } else { + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + return; + break; + } + fAckAlarm (tvb, pinfo, tree, offset); +} + +void +fAckAlarmRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* acknowledgingProcessId */ + fUnsignedTag (tvb, tree, offset, "acknowledgingProcessId: ", lvt); + break; + case 1: /* eventObjectId */ + fObjectIdentifier (tvb, tree, offset, "eventObjectId: "); + break; + case 2: /* eventStateAcknowledged */ + fApplicationTags (tvb, tree, offset, "eventStateAcknowledged: ", bacapp_EventState); + break; + case 3: /* timeStamp */ + fTimeTag (tvb, tree, offset, "timeStamp: ", lvt); + break; + case 4: /* acknowledgementSource */ + fApplicationTags (tvb, tree, offset, "acknowledgementSource: ", NULL); + break; + case 5: /* timeOfAcknowledgement */ + fTimeTag (tvb, tree, offset, "timeOfAcknowledgement: ", lvt); + break; + default: + return; + break; + } + fAckAlarmRequest (tvb, pinfo, tree, offset); +} + +void +fGetAlarmSummary (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + fObjectIdentifier (tvb, tree, offset, "objectIdentifier: "); + fApplicationTags (tvb, tree, offset, "alarmState: ", bacapp_EventState); + fApplicationTags (tvb, tree, offset, "acknowledgedTransitions: ", bacapp_EventTransitionBits); + + fGetAlarmSummary (tvb, pinfo, tree, offset); +} + +void +fgetEnrollmentSummaryRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* acknowledgmentFilter */ + fApplicationTags (tvb, tree, offset, "acknowledgmentFilter: ", bacapp_AcknowledgementFilter); + break; + case 1: /* eventObjectId */ + fRecipientProcess (tvb, pinfo, tree, offset); + break; + case 2: /* eventStateFilter */ + fApplicationTags (tvb, tree, offset, "eventStateFilter: ", bacapp_eventStateFilter); + break; + case 3: /* eventTypeFilter */ + fApplicationTags (tvb, tree, offset, "eventTypeFilter: ", bacapp_EventType); + break; + case 4: /* priorityFilter */ + (*offset)++; + fUnsignedTag (tvb, tree, offset, "minPriority: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fUnsignedTag (tvb, tree, offset, "maxPriority: ", lvt); + break; + case 5: /* notificationClassFilter */ + fUnsignedTag (tvb, tree, offset, "notificationClassFilter: ", lvt); + break; + default: + return; + break; + } + fgetEnrollmentSummaryRequest (tvb, pinfo, tree, offset); +} + +void +fgetEnrollmentSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + fObjectIdentifier (tvb, tree, offset, "ObjectId: "); + fApplicationTags (tvb, tree, offset, "eventType: ", bacapp_EventType); + fApplicationTags (tvb, tree, offset, "eventState: ", bacapp_eventStateFilter); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fUnsignedTag (tvb, tree, offset, "Priority: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fUnsignedTag (tvb, tree, offset, "notificationClass: ", lvt); + + fgetEnrollmentSummaryAck (tvb, pinfo, tree, offset); +} + +void +fGetEventInformationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* lastReceivedObjectId */ + fObjectIdentifier (tvb, tree, offset, "lastReceivedObjectId: "); + break; + default: + return; + break; + } + fGetEventInformationRequest (tvb, pinfo, tree, offset); +} + +void +flistOfEventSummaries (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* ObjectId */ + fObjectIdentifier (tvb, tree, offset, "ObjectId: "); + break; + case 1: /* eventState */ + fApplicationTags (tvb, tree, offset, "eventState: ", bacapp_eventStateFilter); + break; + case 2: /* acknowledgedTransitions */ + fApplicationTags (tvb, tree, offset, "acknowledgedTransitions: ", bacapp_EventTransitionBits); + break; + case 3: /* eventTimeStamps */ + fTimeTag (tvb, tree, offset, "timeStamp: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fTimeTag (tvb, tree, offset, "timeStamp: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fTimeTag (tvb, tree, offset, "timeStamp: ", lvt); + break; + case 4: /* notifyType */ + fApplicationTags (tvb, tree, offset, "NotifyType: ", bacapp_NotifyType); + break; + case 5: /* eventEnable */ + fApplicationTags (tvb, tree, offset, "eventEnable: ", bacapp_EventTransitionBits); + break; + case 6: /* eventPriorities */ + fUnsignedTag (tvb, tree, offset, "eventPriority: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fUnsignedTag (tvb, tree, offset, "eventPriority: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fUnsignedTag (tvb, tree, offset, "eventPriority: ", lvt); + break; + default: + return; + break; + } + flistOfEventSummaries (tvb, pinfo, tree, offset); +} + +void +fGetEventInformation (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* listOfEventSummaries */ + flistOfEventSummaries (tvb, pinfo, tree, offset); + break; + case 1: /* moreEvents */ + fApplicationTags (tvb, tree, offset, "moreEvents: ", NULL); + break; + default: + return; + break; + } + fGetEventInformationRequest (tvb, pinfo, tree, offset); +} + +void +fAddListElement (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* ObjectId */ + fObjectIdentifier (tvb, tree, offset, "ObjectId: "); + break; + case 1: /* propertyIdentifier */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: "); + break; + case 2: /* propertyArrayIndex */ + (*offset)+= offs; + fSignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt); + break; + case 3: /* propertyValue */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Elements {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + return; + break; + } + fAddListElement (tvb, pinfo, tree, offset); +} + +void +fDeleteObject (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); +} + +void +fWritePropertyMultiple (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fDeviceCommunicationControl (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fReinitializeDevice (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fVtOpen (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fVtClose (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fVtData (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fAuthenticate (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fRequestKey (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fLifeSafetyOperation (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fSubscribeCOVProperty (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fRemoveListElement (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + if ((*offset) >= tvb->length) + return; + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ + +} + +void +fReadWriteProperty (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectIdentifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + case 1: /* propertyIdentifier */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: "); + break; + case 2: /* propertyArrayIndex */ + (*offset)+= offs; + fSignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt); + break; + case 3: /* propertyValue */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + /* return; */ + } + break; + case 4: /* Priority */ + (*offset)+= offs; + fSignedTag (tvb, tree, offset, "Priority: ", lvt); + break; + default: + proto_tree_add_text(tree, tvb, (*offset)++, 1, "unknown"); + return; + } + fReadWriteProperty (tvb, pinfo, tree, offset); +} + + +void +fPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + if (lvt == 7) /* closing bracket */ + return; + + switch (tag_no) { + case 0: /* PropertyIdentifier */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: "); + break; + case 1: /* propertyArrayIndex */ + (*offset)+= offs; + fUnsignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt); + break; + default: + return; + } + fPropertyReference (tvb, pinfo, tree, offset); +} + +void +fSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* selectionLogic */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: "); + break; + case 1: /* propertyArrayIndex */ + (*offset)+= offs; + fUnsignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt); + break; + case 2: /* relationSpecifier */ + fApplicationTags (tvb, tree, offset, "relationSpecifier: ", bacapp_relationSpecifier); + break; + case 3: /* comparisonValue */ + fApplicationTags (tvb, tree, offset, "comparisonValue: ", NULL); + break; + default: + return; + } + fSelectionCriteria (tvb, pinfo, tree, offset); +} + +void +fObjectSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* selectionLogic */ + fApplicationTags (tvb, tree, offset, "selectionLogic: ", bacapp_selectionLogic); + break; + case 1: /* listOfSelectionCriteria */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of PropertyReferences {"); + } + fSelectionCriteria (tvb, pinfo, tree, offset); + + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + return; + } + fObjectSelectionCriteria (tvb, pinfo, tree, offset); +} + + +void +fReadPropertyConditional (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectSelectionCriteria */ + fObjectSelectionCriteria (tvb, pinfo, tree, offset); + break; + case 1: /* listOfPropertyReferences */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of PropertyReferences {"); + } + fPropertyReference (tvb, pinfo, tree, offset); + + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + return; + } + fReadPropertyConditional (tvb, pinfo, tree, offset); +} + +void +fReadWriteMultipleProperty (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + /* not yet implemented */ + *pinfo = *pinfo; /* just to eliminate warnings */ + *tree = *tree; /* just to eliminate warnings */ +} + +void +fReadAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectIdentifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + case 1: /* listOfPropertyReferences */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of PropertyReferences {"); + } + fPropertyReference (tvb, pinfo, tree, offset); + + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + return; + } + fReadAccessSpecification (tvb, pinfo, tree, offset); +} + +void +fWriteAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectIdentifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + case 1: /* listOfPropertyValues */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of PropertyValues {"); + } + fPropertyValue (tvb, pinfo, tree, offset); + + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + return; + } + fReadAccessSpecification (tvb, pinfo, tree, offset); +} + +void +fReadAccessResult (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectIdentifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + case 1: /* listOfResults */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Results {"); + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + case 2: /* propertyIdentifier */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: "); + break; + case 3: /* propertyArrayIndex */ + (*offset)+= offs; + fUnsignedTag (tvb, tree, offset, "propertyArrayIndex: ", lvt); + break; + case 4: /* propertyValue */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + case 5: /* propertyAccessError */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Errors {"); + /* Error Code follows */ + fApplicationTags (tvb, tree, offset, " errorClass: ", bacapp_errorClass); + fApplicationTags (tvb, tree, offset, " errorCode: ", bacapp_error_code); + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + default: + return; + } + fReadAccessResult (tvb, pinfo, tree, offset); +} + + +void +fReadPropertyConditionalAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + /* listOfReadAccessResults */ + fReadAccessResult (tvb, pinfo, tree, offset); + fReadPropertyConditionalAck (tvb, pinfo, tree, offset); +} + + +void +fObjectSpecifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectType */ + proto_tree_add_item(tree, hf_bacapp_tag_initiatingObjectType, tvb, (*offset), 1, TRUE); + break; + case 1: /* objectIdentifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + } + fObjectSpecifier (tvb, pinfo, tree, offset); +} + + + +void +fCreateObject (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectSpecifier */ + fObjectSpecifier (tvb, pinfo, tree, offset); + break; + case 1: /* propertyValue */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + proto_tree_add_text(tree, tvb, (*offset)++, 1, "unknown"); + return; + } + fCreateObject (tvb, pinfo, tree, offset); +} + +void +fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); +} + +void +fReadRangeRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectSpecifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + case 1: /* propertyIdentifier */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: "); + break; + case 2: /* propertyArrayIndex Optional */ + fUnsignedTag (tvb, tree, offset, "PropertyArrayIndex: ", lvt); + break; + case 3: /* range byPosition */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "range byPosition: referenceIndex, count {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + case 4: /* range byTime */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "range byTime: referenceTime, count {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + case 5: /* range timeRange */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "TimeRange: beginningTime, endingTime {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + return; + } + fReadRangeRequest (tvb, pinfo, tree, offset); +} + +void +fReadRangeAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectSpecifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + case 1: /* propertyIdentifier */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: "); + break; + case 2: /* propertyArrayIndex Optional */ + fUnsignedTag (tvb, tree, offset, "PropertyArrayIndex: ", lvt); + break; + case 3: /* resultFlags */ + fApplicationTags (tvb, tree, offset, "resultFlags: ", bacapp_resultFlags); + break; + case 4: /* itemCount */ + fUnsignedTag (tvb, tree, offset, "itemCount: ", lvt); + break; + case 5: /* itemData */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "List Of Values {"); + fApplicationTags (tvb, tree, offset, " Data: ", NULL); + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + return; + } + break; + default: + return; + } + fReadRangeAck (tvb, pinfo, tree, offset); +} + +void +fAtomicReadFileRequest (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* streamAccess */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {"); + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fSignedTag (tvb, tree, offset, " FileStartPosition: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fUnsignedTag (tvb, tree, offset, " requestetOctetCount: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + case 1: /* recordAccess */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "recordAccess {"); + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fSignedTag (tvb, tree, offset, " FileStartRecord: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fUnsignedTag (tvb, tree, offset, " requestetRecordCount: ", lvt); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + default: + return; + } +} + +void +fAtomicWriteFileRequest (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) { /* Segment of an Request */ + if (bacapp_flags & 0x04) { /* More Flag is set */ + fOctetString (tvb, tree, offset, " fileData: ", 0); + } else { + fOctetString (tvb, tree, offset, " fileData: ", tvb->length - *offset - 1); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (lvt == 7) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + } + } else { + fObjectIdentifier (tvb, tree, offset, "fileIdentifier: "); + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* streamAccess */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {"); + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fSignedTag (tvb, tree, offset, " FileStartPosition: ", lvt); + fApplicationTags (tvb, tree, offset, " fileData: ", NULL); + if (bacapp_flags && 0x04) { /* More Flag is set */ + break; + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + case 1: /* recordAccess */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {"); + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fSignedTag (tvb, tree, offset, " fileStartRecord: ", lvt); + fUnsignedTag (tvb, tree, offset, " RecordCount: ", lvt); + fApplicationTags (tvb, tree, offset, " Data: ", NULL); + if (bacapp_flags && 0x04) { /* More Flag is set */ + break; + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + default: + return; + } + } +} + +void +fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* streamAccess */ + fSignedTag (tvb, tree, offset, " FileStartPosition: ", lvt); + break; + case 1: /* recordAccess */ + fSignedTag (tvb, tree, offset, " fileStartRecord: ", lvt); + break; + default: + return; + } +} + +void +fAtomicReadFile (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) { /* Segment of an Request */ + if (bacapp_flags & 0x04) { /* More Flag is set */ + fOctetString (tvb, tree, offset, " fileData: ", 0); + } else { + fOctetString (tvb, tree, offset, " fileData: ", tvb->length - *offset - 1); + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (lvt == 7) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + } + } else { + fApplicationTags (tvb, tree, offset, "EndOfFile: ", NULL); + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* streamAccess */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {"); + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fSignedTag (tvb, tree, offset, " FileStartPosition: ", lvt); + fApplicationTags (tvb, tree, offset, " fileData: ", NULL); + if (bacapp_flags && 0x04) { /* More Flag is set */ + break; + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + case 1: /* recordAccess */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "streamAccess {"); + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fSignedTag (tvb, tree, offset, " FileStartRecord: ", lvt); + fUnsignedTag (tvb, tree, offset, " returnedRecordCount: ", lvt); + fApplicationTags (tvb, tree, offset, " Data: ", NULL); + if (bacapp_flags && 0x04) { /* More Flag is set */ + break; + } + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + default: + return; + } + } +} + +void +fReadPropertyMultipleRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectSpecifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + case 1: /* list of propertyReferences */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {"); + fPropertyReference (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + default: + return; + } + fReadPropertyMultipleRequest (tvb, pinfo, tree, offset); +} + +void +fReadPropertyMultipleAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (tag_no) { + case 0: /* objectSpecifier */ + fObjectIdentifier (tvb, tree, offset, "BACnetObjectIdentifier: "); + break; + case 1: /* list of Results */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Results {"); + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + case 2: /* propertyIdentifier */ + propertyIdentifier = fPropertyIdentifier (tvb, tree, offset, "property Identifier: "); + break; + case 3: /* propertyArrayIndex Optional */ + fUnsignedTag (tvb, tree, offset, "PropertyArrayIndex: ", lvt); + break; + case 4: /* propertyValue */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Values {"); + fPropertyValue (tvb, pinfo, tree, offset); /* use pointer, not value of offset !!!! */ + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + case 5: /* propertyAccessError */ + (*offset) += offs; /* set offset according to enhancements.... */ + if ((lvt == 6) && (offs == 0)) { /* opening Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, max(offs,1), "list of Errors {"); + /* Error Code follows */ + fApplicationTags (tvb, tree, offset, " errorClass: ", bacapp_errorClass); + fApplicationTags (tvb, tree, offset, " errorCode: ", bacapp_error_code); + } + if (((lvt == 7) && (offs == 0))) { /* closing Tag */ + proto_tree_add_text(tree, tvb, (*offset)++, 1, "}"); + } + break; + default: + return; + } + fReadPropertyMultipleAck (tvb, pinfo, tree, offset); +} + +void +fTagRequests (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset, gint service_choice) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + +// if (class_tag) { /* Context Specific Tag detected */ + switch (service_choice) { + case 0: /* acknowledgeAlarm */ + fAckAlarmRequest (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 1: /* confirmedCOVNotification*/ + fCOVNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 2: /* confirmedEventNotification*/ + fEventNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 3: /* confirmedEventNotification*/ + fGetAlarmSummary (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 4: /* getEnrollmentSummaryRequest */ + fgetEnrollmentSummaryRequest (tvb, pinfo, tree, offset); + break; + case 5: /* subscribeCOVRequest */ + fSubscribeCOV (tvb, pinfo, tree, offset); + break; + case 6: /* atomicReadFile-Request */ + fAtomicReadFileRequest (tvb, tree, offset); + break; + case 7: /* atomicReadFile-Request */ + fAtomicWriteFileRequest (tvb, tree, offset); + break; + case 8: /* AddListElement-Request */ + fAddListElement (tvb, pinfo, tree, offset); + break; + case 9: /* removeListElement-Request */ + fRemoveListElement (tvb, pinfo, tree, offset); + break; + case 10: /* createObjectRequest */ + fCreateObject (tvb, pinfo, tree, offset); + break; + case 11: /* deleteObject */ + fDeleteObject (tvb, tree, offset); + break; + case 12: + fReadWriteProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 13: + fReadPropertyConditional (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 14: + fReadPropertyMultipleRequest (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 15: + fReadWriteProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 16: + fReadWriteMultipleProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 17: + fDeviceCommunicationControl (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 18: + fPrivateTransfer (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 19: + fTextMessage (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 20: + fReinitializeDevice (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 21: + fVtOpen (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 22: + fVtClose (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 23: + fVtData (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 24: + fAuthenticate (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 25: + fRequestKey (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 26: + fReadRangeRequest (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 27: + fLifeSafetyOperation (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 28: + fSubscribeCOVProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 29: + fGetEventInformationRequest (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + default: + return; + break; + } +// } else { /* Application Specific Tags */ +// fApplicationTags (tvb, tree, offset, NULL, NULL); +// } + + /* fTagRequests (tvb, pinfo, tree, offset, service_choice); ### */ +} + +void +fTags (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset, gint service_choice) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + +// if (class_tag) { /* Context Specific Tag detected */ + switch (service_choice) { + case 0: /* acknowledgeAlarm */ + fAckAlarm (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 1: /* confirmedCOVNotification*/ + fCOVNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 2: /* confirmedEventNotification*/ + fEventNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 3: /* confirmedEventNotification*/ + fGetAlarmSummary (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 4: /* getEnrollmentSummaryAck */ + fgetEnrollmentSummaryAck (tvb, pinfo, tree, offset); + break; + case 5: /* subscribeCOV */ + fSubscribeCOV (tvb, pinfo, tree, offset); + break; + case 6: /* atomicReadFile */ + fAtomicReadFile (tvb, tree, offset); + break; + case 7: /* atomicReadFileAck */ + fAtomicWriteFileAck (tvb, tree, offset); + break; + case 8: /* AddListElement */ + fAddListElement (tvb, pinfo, tree, offset); + break; + case 9: /* removeListElement */ + fRemoveListElement (tvb, pinfo, tree, offset); + break; + case 10: /* createObject */ + fCreateObjectAck (tvb, tree, offset); + break; + case 11: /* deleteObject */ + fDeleteObject (tvb, tree, offset); + break; + case 12: + fReadWriteProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 13: + fReadPropertyConditionalAck (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 14: + fReadPropertyMultipleAck (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 15: + fReadWriteProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 16: + fReadWriteMultipleProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 17: + fDeviceCommunicationControl (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 18: + fPrivateTransfer (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 19: + fTextMessage (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 20: + fReinitializeDevice (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 21: + fVtOpen (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 22: + fVtClose (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 23: + fVtData (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 24: + fAuthenticate (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 25: + fRequestKey (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 26: + fReadRangeAck (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 27: + fLifeSafetyOperation (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 28: + fSubscribeCOVProperty (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 29: + fGetEventInformation (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + default: + return; + break; + } +// } else { /* Application Specific Tags */ +// fApplicationTags (tvb, pinfo, tree, offset, NULL, NULL); +// } +} + +void +fIAm (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + guint8 offs, tmp, tag_no, class_tag, i; + guint64 lvt; + guint32 val = 0; + + /* BACnetObjectIdentifier */ + fApplicationTags (tvb, tree, offset, "BACnetObjectIdentifier: ", NULL); + + /* MaxAPDULengthAccepted */ + fApplicationTags (tvb, tree, offset, "Maximum ADPU Length accepted: ", NULL); + + /* segmentationSupported */ + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + (*offset) += offs + 1; /* set offset according to enhancements.... */ + for (i = 0; i < min((guint8) lvt, 4); i++) { + tmp = tvb_get_guint8(tvb, (*offset)+i); + val = (val << 8) + tmp; + } + proto_tree_add_text(tree, tvb, *offset, 1, "segmentationSupported: %s", match_strval(val, bacapp_segmentation)); + (*offset)+=(guint8)lvt; + + /* vendor ID */ + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + fUnsignedTag (tvb, tree, offset, "vendorID: ", lvt); + +} + +void +fIHave (tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ + /* BACnetDeviceIdentifier */ + fApplicationTags (tvb, tree, offset, "DeviceIdentifier: ", NULL); + + /* BACnetObjectIdentifier */ + fApplicationTags (tvb, tree, offset, "ObjectIdentifier: ", NULL); + + /* ObjectName */ + fApplicationTags (tvb, tree, offset, "ObjectName: ", NULL); + +} + +void +fWhoIs (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ + guint8 tag_no, class_tag; + guint64 lvt; + + if ((*offset) >= tvb->length) + return; + + (*offset) += fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + + switch (tag_no) { + case 0: /* DeviceInstanceRangeLowLimit Optional */ + fUnsignedTag (tvb, tree, offset, "DeviceInstanceRangeLowLimit: ", lvt); + break; + case 1: /* DeviceInstanceRangeHighLimit Optional but required if DeviceInstanceRangeLowLimit is there */ + fUnsignedTag (tvb, tree, offset, "DeviceInstanceRangeHighLimit: ", lvt); + break; + default: + return; + break; + } + fWhoIs (tvb, pinfo, tree, offset); +} + +void +fUnconfirmedTags (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset, gint service_choice) +{ + guint8 offs, tag_no, class_tag; + guint64 lvt; + + if (*offset >= tvb->length) + return; + + offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt); + + switch (service_choice) { + case 0: /* I-Am-Request */ + fIAm (tvb, tree, offset); /* offset changes his value on return */ + break; + case 1: /* i-Have Request */ + fIHave (tvb, tree, offset); /* offset changes his value on return */ + break; + case 2: /* unconfirmedCOVNotification */ + fCOVNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 3: /* unconfirmedEventNotification */ + fEventNotification (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 4: /* unconfirmedPrivateTransfer */ + fPrivateTransfer (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 5: /* unconfirmedTextMessage */ + fTextMessage (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 6: /* timeSynchronization */ + fTimeSynchronization (tvb, tree, offset); /* offset changes his value on return */ + break; + case 7: /* who-Has */ + fWhoHas (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 8: /* who-Is */ + fWhoIs (tvb, pinfo, tree, offset); /* offset changes his value on return */ + break; + case 9: /* utcTimeSynchronization */ + fUTCTimeSynchronization (tvb, tree, offset); /* offset changes his value on return */ + break; + default: + break; + } +} + +void +fConfirmedServiceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ /* BACnet-Confirmed-Request */ + /* ASHRAE 135-2001 20.1.2 */ + + proto_item *tc, *tt, *ti; + proto_tree *bacapp_tree, *bacapp_tree_control, *bacapp_tree_tag; + gint tmp, bacapp_type, service_choice; + + tmp = (gint) tvb_get_guint8(tvb, (*offset)); + bacapp_type = (tmp >> 4) & 0x0f; + bacapp_flags = tmp & 0x0f; + + service_choice = (gint) tvb_get_guint8(tvb, (*offset)+3); + if (bacapp_flags & 0x08) + service_choice = (gint) tvb_get_guint8(tvb, (*offset)+5); + + + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, val_to_str(service_choice, bacapp_confirmed_service_choice, "Reserved by ASHRAE")); + + if (tree) { + + ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); + + tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset), 1, TRUE); + bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); + + proto_tree_add_item(bacapp_tree_control, hf_bacapp_SEG, tvb, (*offset), 1, TRUE); + proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, (*offset), 1, TRUE); + proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, (*offset)++, 1, TRUE); + proto_tree_add_item(bacapp_tree_control, hf_bacapp_response_segments, tvb, + (*offset), 1, TRUE); + proto_tree_add_item(bacapp_tree_control, hf_bacapp_max_adpu_size, tvb, + (*offset), 1, TRUE); + (*offset) ++; + proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, (*offset)++, 1, TRUE); + if (bacapp_flags & 0x08) { + bacapp_seq = tvb_get_guint8(tvb, (*offset)); + proto_tree_add_item(bacapp_tree_control, hf_bacapp_sequence_number, tvb, + (*offset)++, 1, TRUE); + proto_tree_add_item(bacapp_tree_control, hf_bacapp_window_size, tvb, + (*offset)++, 1, TRUE); + } + tmp = tvb_get_guint8(tvb, (*offset)); + proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb, + (*offset)++, 1, TRUE); + tt = proto_tree_add_item(bacapp_tree, hf_bacapp_vpart, tvb, + (*offset), 0, TRUE); + /* Service Request follows... Variable Encoding 20.2ff */ + bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag); + fTagRequests (tvb, pinfo, bacapp_tree_tag, offset, tmp); /* (*offset) changes his value on return */ + } +} + +void +fUnconfirmedServiceRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ /* BACnet-Unconfirmed-Request-PDU */ + /* ASHRAE 135-2001 20.1.3 */ + + proto_item *tt, *ti; + proto_tree *bacapp_tree_tag, *bacapp_tree; + gint tmp; + + tmp = tvb_get_guint8(tvb, (*offset)+1); + if (check_col(pinfo->cinfo, COL_INFO)) + col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tmp, BACnetUnconfirmedServiceRequest, "Reserved by ASHRAE")); + + if (tree) { + ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); + + proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset)++, 1, TRUE); + + tmp = tvb_get_guint8(tvb, (*offset)); + tt = proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb, + (*offset)++, 1, TRUE); + /* Service Request follows... Variable Encoding 20.2ff */ + bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag); + fUnconfirmedTags (tvb, pinfo, bacapp_tree_tag, offset, tmp); /* (*offset) changes his value on return */ + } +} + +void +fSimpleAcknowledge(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ /* BACnet-Simple-Ack-PDU */ + /* ASHRAE 135-2001 20.1.4 */ + + proto_item *tc, *ti; + gint tmp; proto_tree *bacapp_tree; - guint8 offset; - guint8 bacapp_type; - tvbuff_t *next_tvb; - if (check_col(pinfo->cinfo, COL_PROTOCOL)) - col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU"); + tmp = tvb_get_guint8(tvb, (*offset)+2); if (check_col(pinfo->cinfo, COL_INFO)) - col_add_str(pinfo->cinfo, COL_INFO, "BACnet APDU "); + col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tmp, bacapp_confirmed_service_choice, "Reserved by ASHRAE")); - offset = 0; - bacapp_type = (tvb_get_guint8(tvb, offset) >> 4) & 0x0f; + if (tree) { + ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); + tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset)++, 1, TRUE); + + proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, + (*offset)++, 1, TRUE); + proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb, + (*offset)++, 1, TRUE); + } +} + +void +fComplexAcknowledge(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint *offset) +{ /* BACnet-Complex-Ack-PDU */ + /* ASHRAE 135-2001 20.1.5 */ + + proto_item *tc, *tt, *ti; + proto_tree *bacapp_tree, *bacapp_tree_control, *bacapp_tree_tag; + gint tmp, bacapp_type; + + tmp = (gint) tvb_get_guint8(tvb, (*offset)); + bacapp_type = (tmp >> 4) & 0x0f; + bacapp_flags = tmp & 0x0f; + + tmp = tvb_get_guint8(tvb, (*offset)+2); + if (bacapp_flags & 0x08) + tmp = tvb_get_guint8(tvb, (*offset)+4); + if (check_col(pinfo->cinfo, COL_INFO)) - col_append_fstr(pinfo->cinfo, COL_INFO, "(%s)", - bacapp_type_name(bacapp_type)); + col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tmp, bacapp_confirmed_service_choice, "Reserved by ASHRAE")); + if (tree) { - ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE); + ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE); bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); - proto_tree_add_uint_format(bacapp_tree, hf_bacapp_type, tvb, - offset, 1, bacapp_type, "APDU Type: %u (%s)", bacapp_type, - bacapp_type_name(bacapp_type)); - offset ++; + tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset), 1, TRUE); + bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); + proto_tree_add_item(bacapp_tree, hf_bacapp_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); + fTags (tvb, pinfo, bacapp_tree_tag, offset, tmp); /* (*offset) changes his value on return */ } - next_tvb = tvb_new_subset(tvb,offset,-1,-1); - call_dissector(data_handle,next_tvb, pinfo, tree); } void +fSegmentedAcknowledge(tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ /* BACnet-SegmentAck-PDU */ + /* ASHRAE 135-2001 20.1.6 */ + + proto_item *tc, *ti; + proto_tree *bacapp_tree_control, *bacapp_tree; + + if (tree) { + ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); + + 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); + } +} + +void +fError(tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ /* BACnet-Error-PDU */ + /* ASHRAE 135-2001 20.1.7 */ + + proto_item *tc, *ti; + proto_tree *bacapp_tree_control, *bacapp_tree; + + if (tree) { + ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); + + tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset)++, 1, TRUE); + bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); + + proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, + (*offset)++, 1, TRUE); + proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb, + (*offset)++, 1, TRUE); + /* Error Code follows */ + fApplicationTags (tvb, bacapp_tree, offset, " errorClass: ", bacapp_errorClass); + fApplicationTags (tvb, bacapp_tree, offset, " errorCode: ", bacapp_error_code); + + } +} + +void +fReject(tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ /* BACnet-Reject-PDU */ + /* ASHRAE 135-2001 20.1.8 */ + + proto_item *tc, *ti; + proto_tree *bacapp_tree_control, *bacapp_tree; + + if (tree) { + ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); + + tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset)++, 1, TRUE); + bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); + + proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, + (*offset)++, 1, TRUE); + proto_tree_add_item(bacapp_tree, hf_bacapp_reject_reason, tvb, + (*offset)++, 1, TRUE); + } +} + +void +dissect_bacapp_abort(tvbuff_t *tvb, proto_tree *tree, guint *offset) +{ /* BACnet-Abort-PDU */ + /* ASHRAE 135-2001 20.1.9 */ + + proto_item *tc, *ti; + proto_tree *bacapp_tree_control, *bacapp_tree; + + if (tree) { + ti = proto_tree_add_item(tree, proto_bacapp, tvb, (*offset), -1, FALSE); + bacapp_tree = proto_item_add_subtree(ti, ett_bacapp); + + tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, (*offset), 1, TRUE); + bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp); + + proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, (*offset)++, 1, TRUE); + proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, + (*offset)++, 1, TRUE); + proto_tree_add_item(bacapp_tree, hf_bacapp_abort_reason, tvb, + (*offset)++, 1, TRUE); + } +} + +void +dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) +{ + gint tmp, bacapp_type; + tvbuff_t *next_tvb; + guint offset = 0; + + tmp = (gint) tvb_get_guint8(tvb, 0); + bacapp_type = (tmp >> 4) & 0x0f; + + if (check_col(pinfo->cinfo, COL_INFO)) + col_set_str(pinfo->cinfo, COL_INFO, val_to_str(bacapp_type, bacapp_type_name, "#### unknown APDU ##### ")); + + /* ASHRAE 135-2001 20.1.1 */ + switch (bacapp_type) { + case 0: /* BACnet-Confirmed-Service-Request */ + fConfirmedServiceRequest(tvb, pinfo, tree, &offset); /* offset will be modified */ + break; + case 1: /* BACnet-Unconfirmed-Request-PDU */ + fUnconfirmedServiceRequest(tvb, pinfo, tree, &offset); /* offset will be modified */ + break; + case 2: /* BACnet-Simple-Ack-PDU */ + fSimpleAcknowledge(tvb, pinfo, tree, &offset); /* offset will be modified */ + break; + case 3: /* BACnet-Complex-Ack-PDU */ + fComplexAcknowledge(tvb, pinfo, tree, &offset); /* offset will be modified */ + break; + case 4: /* BACnet-SegmentAck-PDU */ + fSegmentedAcknowledge(tvb, tree, &offset); /* offset will be modified */ + break; + case 5: /* BACnet-Error-PDU */ + fError(tvb, tree, &offset); /* offset will be modified */ + break; + case 6: /* BACnet-Reject-PDU */ + fReject(tvb, tree, &offset); /* offset will be modified */ + break; + case 7: /* BACnet-Abort-PDU */ + dissect_bacapp_abort(tvb, tree, &offset); /* offset will be modified */ + break; + } + + next_tvb = tvb_new_subset(tvb,offset,-1,tvb->reported_length - offset); + call_dissector(data_handle,next_tvb, pinfo, tree); +} + +void proto_register_bacapp(void) { static hf_register_info hf[] = { { &hf_bacapp_type, { "APDU Type", "bacapp.bacapp_type", - FT_UINT8, BASE_DEC, NULL, 0xf0, "APDU Type", HFILL } + FT_UINT8, BASE_DEC, VALS(bacapp_type_name), 0xf0, "APDU Type", HFILL } }, + { &hf_bacapp_SEG, + { "SEG", "bacapp.bacapp_type.SEG", + FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, "Segmented Requests", HFILL } + }, + { &hf_bacapp_MOR, + { "MOR", "bacapp.bacapp_type.MOR", + FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL } + }, + { &hf_bacapp_SA, + { "SA", "bacapp.bacapp_type.SA", + FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL } + }, + { &hf_bacapp_max_adpu_size, + { "Size of Maximum ADPU accepted", "bacapp.bacapp_max_adpu_size", + FT_UINT8, BASE_DEC, VALS(bacapp_max_APDU_length_accepted), 0x0f, "Size of Maximum ADPU accepted", HFILL } + }, + { &hf_bacapp_response_segments, + { "Max Response Segments accepted", "bacapp.bacapp_response_segments", + FT_UINT8, BASE_DEC, VALS(bacapp_max_segments_accepted), 0xe0, "Max Response Segments accepted", HFILL } + }, + { &hf_bacapp_invoke_id, + { "Invoke ID", "bacapp.bacapp_invoke_id", + FT_UINT8, BASE_HEX, NULL, 0, "Invoke ID", HFILL } + }, + { &hf_bacapp_sequence_number, + { "Sequence Number", "bacapp.bacapp_sequence_number", + FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL } + }, + { &hf_bacapp_window_size, + { "Proposed Window Size", "bacapp.bacapp_window_size", + FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL } + }, + { &hf_bacapp_service, + { "Service Choice", "bacapp.bacapp_service", + FT_UINT8, BASE_DEC, VALS(bacapp_confirmed_service_choice), 0x00, "Service Choice", HFILL } + }, + { &hf_bacapp_uservice, + { "Unconfirmed Service Choice", "bacapp.bacapp_unconfirmed_service", + FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, "Unconfirmed Service Choice", HFILL } + }, + { &hf_bacapp_NAK, + { "NAK", "bacapp.bacapp_type.NAK", + FT_BOOLEAN, 8, NULL, 0x02, "negativ ACK", HFILL } + }, + { &hf_bacapp_SRV, + { "SRV", "bacapp.bacapp_type.SRV", + FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL } + }, + { &hf_bacapp_reject_reason, + { "Reject Reason", "bacapp.bacapp_reject_reason", + FT_UINT8, BASE_DEC, VALS(bacapp_reject_reason), 0x00, "Reject Reason", HFILL } + }, + { &hf_bacapp_abort_reason, + { "Abort Reason", "bacapp.bacapp_abort_reason", + FT_UINT8, BASE_DEC, VALS(bacapp_abort_reason), 0x00, "Abort Reason", HFILL } + }, + { &hf_bacapp_vpart, + { "BACnet APDU variable part:", "bacapp.variable_part", + FT_NONE, 0, NULL, 00, "BACnet APDU varaiable part:", HFILL } + }, + { &hf_bacapp_tag_number, + { "Tag Number", "bacapp.bacapp_tag.number", + FT_UINT8, BASE_DEC, VALS(bacapp_tag_number), 0xF0, "Tag Number", HFILL } + }, + { &hf_bacapp_tag_class, + { "Class", "bacapp.bacapp_tag.class", + FT_BOOLEAN, 8, TFS(&bacapp_tag_class), 0x08, "Class", HFILL } + }, + { &hf_bacapp_tag_lvt, + { "Length Value Type", "bacapp.bacapp_tag.lvt", + FT_UINT8, BASE_DEC, NULL, 0x07, "Length Value Type", HFILL } + }, +/* { &hf_bacapp_initiatingObject, + { "initiating Object Identifier:", "bacapp.initiatingObject", + FT_NONE, 0, NULL, 0x00, "BACnet APDU InitiatingObject:", HFILL } + }, + { &hf_bacapp_monitoredObject, + { "monitored Object Identifier:", "bacapp.monitoredObject", + FT_NONE, 0, NULL, 0x00, "BACnet APDU MonitoredObject:", HFILL } + }, +*/ { &hf_bacapp_tag_ProcessId, + { "subscriberProcessIdentifier", "bacapp.bacapp_tag.ProcessId", + FT_UINT32, BASE_DEC, NULL, 0, "subscriberProcessIdentifier", HFILL } + }, + { &hf_bacapp_tag_initiatingObjectType, + { "ObjectType", "bacapp.bacapp_tag.ObjectType", + FT_UINT16, BASE_DEC, VALS(bacapp_object_type), 0x00, "ObjectType", HFILL } + }, +/* { &hf_bacapp_tag_initiatingObjectId, + { "instance Number", "bacapp.bacapp_tag.ObjectId", + FT_UINT24, BASE_DEC, NULL, 0, "instance Number", HFILL } + }, + { &hf_bacapp_tag_null, + { " Value - NULL", "bacapp.bacapp_tag.null", + FT_UINT8, BASE_HEX, NULL, 0x07, "Application Tag NULL", HFILL } + }, + { &hf_bacapp_tag_boolean, + { " Value - Boolean", "bacapp.bacapp_tag.boolean", + FT_BOOLEAN, 8, NULL, 0x07, "Application Tag Boolean", HFILL } + }, + { &hf_bacapp_tag_uint8, + { " Value - Unsigned Integer", "bacapp.bacapp_tag.uint8", + FT_UINT8, BASE_DEC, NULL, 0, "Unsigned Integer", HFILL } + }, + { &hf_bacapp_tag_uint16, + { " Value - Unsigned Integer", "bacapp.bacapp_tag.uint16", + FT_UINT16, BASE_DEC, NULL, 0, "Unsigned Integer", HFILL } + }, + { &hf_bacapp_tag_uint32, + { " Value - Unsigned Integer", "bacapp.bacapp_tag.uint32", + FT_UINT32, BASE_DEC, NULL, 0, "Unsigned Integer", HFILL } + }, + { &hf_bacapp_tag_uint64, + { " Value - Unsigned Integer", "bacapp.bacapp_tag.uint64", + FT_UINT64, BASE_DEC, NULL, 0, "Unsigned Integer", HFILL } + }, + { &hf_bacapp_tag_sint8, + { " Value - Signed Integer", "bacapp.bacapp_tag.sint8", + FT_INT8, BASE_DEC, NULL, 0, "Signed Integer", HFILL } + }, + { &hf_bacapp_tag_sint16, + { " Value - Signed Integer", "bacapp.bacapp_tag.sint16", + FT_INT16, BASE_DEC, NULL, 0, "Signed Integer", HFILL } + }, + { &hf_bacapp_tag_sint32, + { " Value - Signed Integer", "bacapp.bacapp_tag.sint32", + FT_INT32, BASE_DEC, NULL, 0, "Signed Integer", HFILL } + }, + { &hf_bacapp_tag_sint64, + { " Value - Signed Integer", "bacapp.bacapp_tag.sint64", + FT_INT64, BASE_DEC, NULL, 0, "Signed Integer", HFILL } + }, + { &hf_bacapp_tag_real, + { " Value - REAL", "bacapp.bacapp_tag.real", + FT_FLOAT, BASE_DEC, NULL, 0, "Real (Floating Point)", HFILL } + }, + { &hf_bacapp_tag_double, + { " Value - DOUBLE", "bacapp.bacapp_tag.double", + FT_DOUBLE, BASE_DEC, NULL, 0, "Double (Double Precision Floating Point)", HFILL } + }, + { &hf_bacapp_tag_timeRemaining, + { "time remaining (seconds)", "bacapp.bacapp_tag.timeRemaining", + FT_UINT64, BASE_DEC, NULL, 0, "time remaining (seconds)", HFILL } + }, + { &hf_bacapp_tag_string, + { " Value - String", "bacapp.bacapp_tag.string", + FT_STRING, BASE_DEC, NULL, 0, "String", HFILL } + }, + { &hf_bacapp_tag_bytes, + { " Value - Bytes", "bacapp.bacapp_tag.bytes", + FT_BYTES, BASE_DEC, NULL, 0, "Bytes", HFILL } + }, + { &hf_bacapp_tag_character_set, + { " Value - String Character Set", "bacapp.bacapp_tag.character_set", + FT_UINT8, BASE_DEC, bacapp_character_set, 0, "Bytes", HFILL } + }, + { &hf_bacapp_error_code, + { "Error Code", "bacapp.bacapp_code", + FT_UINT8, BASE_DEC, VALS(bacapp_error_code), 0x00, "Error Code", HFILL } + }, +*/ }; static gint *ett[] = { &ett_bacapp, + &ett_bacapp_control, + &ett_bacapp_tag, }; 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
- Follow-Ups:
- [Ethereal-dev] Streamed MPEG2 TS dissector
- From: Alex
- Re: [Ethereal-dev] Patch to packet-bacapp.c
- From: ronnie sahlberg
- [Ethereal-dev] Streamed MPEG2 TS dissector
- Prev by Date: [Ethereal-dev] Re: [Ethereal-cvs] rev 13414: /trunk/epan/: stats_tree.c stats_tree.h stats_tree_priv.h /trunk/gtk/: stats_tree_stat.c /trunk/: tap-stats_tree.c
- Next by Date: [Ethereal-dev] Streamed MPEG2 TS dissector
- Previous by thread: [Ethereal-dev] Re: [Ethereal-cvs] rev 13414: /trunk/epan/: stats_tree.c stats_tree.h stats_tree_priv.h /trunk/gtk/: stats_tree_stat.c /trunk/: tap-stats_tree.c
- Next by thread: [Ethereal-dev] Streamed MPEG2 TS dissector
- Index(es):