wireshark/epan/dissectors/packet-bacapp.c

5280 lines
145 KiB
C
Raw Normal View History

/* packet-bacapp.c
* Routines for BACnet (APDU) dissection
* Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
* Enhanced by Steve Karg, 2005, <skarg@users.sourceforge.net>
* Enhanced by Herbert Lischka, 2005, <lischka@kieback-peter.de>, Berlin
*
* $Id$
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@ethereal.com>
* Copyright 1998 Gerald Combs
*
* Copied from README.developer,v 1.23
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "packet-bacapp.h"
static const char *bacapp_unknown_service_str = "unknown service";
static const value_string
BACnetTypeName[] = {
{0, "Confirmed-Request "},
{1, "Unconfirmed-Request "},
{2, "SimpleACK "},
{3, "ComplexACK "},
{4, "SegmentACK "},
{5, "Error "},
{6, "Reject "},
{7, "Abort "},
{0, NULL }
};
static const true_false_string segments_follow = {
"Segmented Request",
"Unsegemented Request"
};
static const true_false_string more_follow = {
"More Segments Follow",
"No More Segments Follow"
};
static const true_false_string segmented_accept = {
"Segmented Response accepted",
"Segmented Response not accepted"
};
static const true_false_string
BACnetTagClass = {
"Context Specific Tag",
"Application Tag"
};
static const value_string
BACnetMaxSegmentsAccepted [] = {
{0,"Unspecified"},
{1,"2 segments"},
{2,"4 segments"},
{3,"8 segments"},
{4,"16 segments"},
{5,"32 segments"},
{6,"64 segments"},
{7,"Greater than 64 segments"},
{0,NULL }
};
static const value_string
BACnetMaxAPDULengthAccepted [] = {
{0,"Up to MinimumMessageSize (50 octets)"},
{1,"Up to 128 octets"},
{2,"Up to 206 octets (fits in a LonTalk frame)"},
{3,"Up to 480 octets (fits in an ARCNET frame)"},
{4,"Up to 1024 octets"},
{5,"Up to 1476 octets (fits in Ethernet II frame)"},
{6,"reserved by ASHRAE"},
{7,"reserved by ASHRAE"},
{8,"reserved by ASHRAE"},
{9,"reserved by ASHRAE"},
{10,"reserved by ASHRAE"},
{11,"reserved by ASHRAE"},
{12,"reserved by ASHRAE"},
{13,"reserved by ASHRAE"},
{14,"reserved by ASHRAE"},
{15,"reserved by ASHRAE"},
{0,NULL}
};
static const value_string
BACnetRejectReason [] = {
{0,"other"},
{1,"buffer-overflow"},
{2,"inconsistent-parameters"},
{3,"invalid-parameter-data-type"},
{4,"invalid-tag"},
{5,"missing-required-parameter"},
{6,"parameter-out-of-range"},
{7,"too-many-arguments"},
{8,"undefined-enumeration"},
{9,"unrecognized-service"},
{10,"reserved by ASHRAE"},
{11,"reserved by ASHRAE"},
{12,"reserved by ASHRAE"},
{13,"reserved by ASHRAE"},
{14,"reserved by ASHRAE"},
{15,"reserved by ASHRAE"},
{0,NULL}
};
static const value_string
BACnetTagNumber [] = {
{0,"Null"},
{1,"Boolean"},
{2,"Unsigned Integer"},
{3,"Signed Integer (2's complement notation)"},
{4,"Real (ANSI/IEE-754 floating point)"},
{5,"Double (ANSI/IEE-754 double precision floating point)"},
{6,"Octet String"},
{7,"Character String"},
{8,"Bit String"},
{9,"Enumerated"},
{10,"Date"},
{11,"Time"},
{12,"BACnetObjectIdentifier"},
{13,"reserved by ASHRAE"},
{14,"reserved by ASHRAE"},
{15,"reserved by ASHRAE"},
{0,NULL}
};
static const value_string
BACnetAction [] = {
{0,"direct"},
{1,"reverse"},
{0,NULL}
};
static const value_string
BACnetFileAccessMethod [] = {
{0,"record-access"},
{1,"stream-access"},
{0,NULL}
};
static const value_string
BACnetAbortReason [] = {
{0,"other"},
{1,"buffer-overflow"},
{2,"invalid-apdu-in-this-state"},
{3,"preempted-by-higher-priority-task"},
{4,"segmentation-not-supported"},
{5,"reserved by ASHRAE"},
{0,NULL}
};
static const value_string
BACnetLifeSafetyMode [] = {
{0,"off"},
{1,"on"},
{2,"test"},
{3,"manned"},
{4,"unmanned"},
{5,"armed"},
{6,"disarmed"},
{7,"prearmed"},
{8,"slow"},
{9,"fast"},
{10,"disconnected"},
{11,"enabledt"},
{12,"disabled"},
{13,"atomic-release-disabled"},
{14,"default"},
{0,NULL}
};
static const value_string
BACnetLifeSafetyOperation [] = {
{0,"none"},
{1,"silence"},
{2,"silence-audible"},
{3,"silence-visual"},
{4,"reset"},
{5,"reset-alarm"},
{6,"reset-fault"},
{7,"reserved by ASHRAE"},
{0,NULL}
};
static const value_string
BACnetLimitEnable [] = {
{0,"lowLimitEnable"},
{1,"highLimitEnable"},
{0,NULL}
};
static const value_string
BACnetLifeSafetyState [] = {
{0,"quiet"},
{1,"pre-alarm"},
{2,"alarm"},
{3,"fault"},
{4,"fault-pre-alarm"},
{5,"fault-alarm"},
{6,"not-ready"},
{7,"active"},
{8,"tamper"},
{9,"test-alarm"},
{10,"test-active"},
{11,"test-fault"},
{12,"test-fault-alarm"},
{13,"holdup"},
{14,"duress"},
{15,"tamper-alarm"},
{16,"abnormal"},
{17,"emergency-power"},
{18,"delayed"},
{19,"blocked"},
{20,"local-alarm"},
{21,"general-alarm"},
{22,"supervisory"},
{23,"test-supervisory"},
{256,"not known"},
{0,NULL}
};
static const value_string
BACnetConfirmedServiceChoice [] = {
{0,"acknowledgeAlarm"},
{1,"confirmedCOVNotification"},
{2,"confirmedEventNotification"},
{3,"getAlarmSummary"},
{4,"getEnrollmentSummary"},
{5,"subscribeCOV"},
{6,"atomicReadFile"},
{7,"atomicWriteFile"},
{8,"addListElement"},
{9,"removeListElement"},
{10,"createObject"},
{11,"deleteObject"},
{12,"readProperty"},
{13,"readPropertyConditional"},
{14,"readPropertyMultiple"},
{15,"writeProperty"}, /* 15 */
{16,"writePropertyMultiple"},
{17,"deviceCommunicationControl"},
{18,"confirmedPrivateTransfer"},
{19,"confirmedTextMessage"},
{20,"reinitializeDevice"},
{21,"vtOpen"},
{22,"vtClose"},
{23,"vtData"},
{24,"authenticate"},
{25,"requestKey"}, /* 25 */
{26,"readRange"},
{27,"lifeSafetyOperation"},
{28,"subscribeCOVProperty"},
{29,"getEventInformation"},
{30,"reserved by ASHRAE"},
{0, NULL}
};
static const value_string
BACnetReliability [] = {
{0,"no-fault-detected"},
{1,"no-sensor"},
{2,"over-range"},
{3,"under-range"},
{4,"open-loop"},
{5,"shorted-loop"},
{6,"no-output"},
{7,"unreliable-other"},
{8,"process-error"},
{9,"multi-state-fault"},
{0,NULL}
};
static const value_string
BACnetUnconfirmedServiceChoice [] = {
{0,"i-Am"},
{1,"i-Have"},
{2,"unconfirmedCOVNotification"},
{3,"unconfirmedEventNotification"},
{4,"unconfirmedPrivateTransfer"},
{5,"unconfirmedTextMessage"},
{6,"timeSynchronization"},
{7,"who-Has"},
{8,"who-Is"},
{9,"utcTimeSynchonization"},
{0,NULL}
};
static const value_string
BACnetUnconfirmedServiceRequest [] = {
{0,"i-Am-Request"},
{1,"i-Have-Request"},
{2,"unconfirmedCOVNotification-Request"},
{3,"unconfirmedEventNotification-Request"},
{4,"unconfirmedPrivateTransfer-Request"},
{5,"unconfirmedTextMessage-Request"},
{6,"timeSynchronization-Request"},
{7,"who-Has-Request"},
{8,"who-Is-Request"},
{9,"utcTimeSynchonization-Request"},
{0,NULL}
};
static const value_string
BACnetObjectType [] = {
{0,"analog-input object"},
{1,"analog-output object"},
{2,"analog-value object"},
{3,"binary-input object"},
{4,"binary-output object"},
{5,"binary-value object"},
{6,"calendar object"},
{7,"command object"},
{8,"device object"},
{9,"event-enrollment object"},
{10,"file object"},
{11,"group object"},
{12,"loop object"},
{13,"multi-state-input object"},
{14,"multi-state-output object"},
{15,"notification-class object"},
{16,"program object"},
{17,"schedule object"},
{18,"averaging object"},
{19,"multi-state-value object"},
{20,"trend-log object"},
{21,"life-safety-point object"},
{22,"life-safety-zone object"},
{0, NULL}
};
static const value_string
BACnetUnits [] = {
{0,"Sq Meters"},
{1,"Sq Feet"},
{2,"Milliamperes"},
{3,"Amperes"},
{4,"Ohms"},
{5,"Volts"},
{6,"Kilovolts"},
{7,"Megavolts"},
{8,"Volt Amperes"},
{9,"Kilovolt Amperes"},
{10,"Megavolt Amperes"},
{11,"Volt Amperes Reactive"},
{12,"Kilovolt Amperes Reactive"},
{13,"Megavolt Amperes Ractive"},
{14,"Degrees Phase"},
{15,"Power Factor"},
{16,"Joules"},
{17,"Kilojoules"},
{18,"Watt Hours"},
{19,"Kilowatt Hours"},
{20,"BTUs"},
{21,"Therms"},
{22,"Ton Hours"},
{23,"Joules Per Kg Dry Air"},
{24,"BTUs Per Pound Dry Air"},
{25,"Cycles Per Hour"},
{26,"Cycles Per Minute"},
{27,"Hertz"},
{28,"Gramms Of Water Per Kilogram Dry Air"},
{29,"Relative Humidity"},
{30,"Millimeters"},
{31,"Meters"},
{32,"Inches"},
{33,"Feed"},
{34,"Watts Per Sq Foot"},
{35,"Watts Per Sq meter"},
{36,"Lumens"},
{37,"Lux"},
{38,"Foot Candels"},
{39,"Kilograms"},
{40,"Pounds Mass"},
{41,"Tons"},
{42,"Kgs per Second"},
{43,"Kgs Per Minute"},
{44,"Kgs Per Hour"},
{45,"Pounds Mass Per Minute"},
{46,"Pounds Mass Per Hour"},
{47,"Watt"},
{48,"Kilowatts"},
{49,"Megawatts"},
{50,"BTUs Per Hour"},
{51,"Horsepower"},
{52,"Tons Refrigeration"},
{53,"Pascals"},
{54,"Kilopascals"},
{55,"Bars"},
{56,"Pounds Force Per Square Inch"},
{57,"Centimeters Of Water"},
{58,"Inches Of Water"},
{59,"Millimeters Of Mercury"},
{60,"Centimeters Of Mercury"},
{61,"Inches Of Mercury"},
{62,"Degrees Celsius"},
{63,"Degress Kelvin"},
{64,"Degrees Fahrenheit"},
{65,"Degree Days Celsius"},
{66,"Degree Days Fahrenheit"},
{67,"Years"},
{68,"Months"},
{69,"Weeks"},
{70,"Days"},
{71,"Hours"},
{72,"Minutes"},
{73,"Seconds"},
{74,"Meters Per Second"},
{75,"Kilometers Per Hour"},
{76,"Feed Per Second"},
{77,"Feet Per Minute"},
{78,"Miles Per Hour"},
{79,"Cubic Feet"},
{80,"Cubic Meters"},
{81,"Imperial Gallons"},
{82,"Liters"},
{83,"US Gallons"},
{84,"Cubic Feet Per Minute"},
{85,"Cubic Meters Per Second"},
{86,"Imperial Gallons Per Minute"},
{87,"Liters Per Second"},
{88,"Liters Per Minute"},
{89,"US Gallons Per Minute"},
{90,"Degrees Angular"},
{91,"Degrees Celsius Per Hour"},
{92,"Degrees Celsius Per Minute"},
{93,"Degrees Fahrenheit Per Hour"},
{94,"Degrees Fahrenheit Per Minute"},
{95,"No Units"},
{96,"Parts Per Million"},
{97,"Parts Per Billion"},
{98,"Percent"},
{99,"Pecent Per Second"},
{100,"Per Minute"},
{101,"Per Second"},
{102,"Psi Per Degree Fahrenheit"},
{103,"Radians"},
{104,"Revolutions Per Min"},
{105,"Currency1"},
{106,"Currency2"},
{107,"Currency3"},
{108,"Currency4"},
{109,"Currency5"},
{110,"Currency6"},
{111,"Currency7"},
{112,"Currency8"},
{113,"Currency9"},
{114,"Currency10"},
{115,"Sq Inches"},
{116,"Sq Centimeters"},
{117,"BTUs Per Pound"},
{118,"Centimeters"},
{119,"Pounds Mass Per Second"},
{120,"Delta Degrees Fahrenheit"},
{121,"Delta Degrees Kelvin"},
{122,"Kilohms"},
{123,"Megohms"},
{124,"Millivolts"},
{125,"Kilojoules Per Kg"},
{126,"Megajoules"},
{127,"Joules Per Degree Kelvin"},
{128,"Joules Per Kg Degree Kelvin"},
{129,"Kilohertz"},
{130,"Megahertz"},
{131,"Per Hour"},
{132,"Milliwatts"},
{133,"Hectopascals"},
{134,"Millibars"},
{135,"Cubic Meters Per Hour"},
{136,"Liters Per Hour"},
{137,"KWatt Hours Per Square Meter"},
{138,"KWatt Hours Per Square Foot"},
{139,"Megajoules Per Square Meter"},
{140,"Megajoules Per Square Foot"},
{141,"Watts Per Sq Meter Degree Kelvin"},
{142,"Cubic Feet Per Second"},
{143,"Percent Obstruction Per Foot"},
{144,"Percent Obstruction Per Meter"},
{256,"Kelvin Per Minute"},
{257,"Minute Per Kelvin"},
{258,"Kelvin Per Hour"},
{0,NULL}
};
static const value_string
BACnetErrorCode [] = {
{0,"other"},
{1,"authentication-failed"},
{2,"character-set-not-supported"},
{3,"configuration-in-progress"},
{4,"device-busy"},
{5,"file-access-denied"},
{6,"incompatible-security-levels"},
{7,"inconsistent-parameters"},
{8,"inconsistent-selection-criterion"},
{9,"invalid-data-type"},
{10,"invalid-file-access-method"},
{11,"invalid-file-start-position"},
{12,"invalid-operator-name"},
{13,"invalid-parameter-data-type"},
{14,"invalid-time-stamp"},
{15,"key-generation-error"},
{16,"missing-required-parameter"},
{17,"no-objects-of-specified-type"},
{18,"no-space-for-object"},
{19,"no-space-to-add-list-element"},
{20,"no-space-to-write-property"},
{21,"no-vt-sessions-available"},
{22,"property-is-not-a-list"},
{23,"object-deletion-not-permitted"},
{24,"object-identifier-already-exists"},
{25,"operational-problem"},
{26,"password-failure"},
{27,"read-access-denied"},
{28,"security-not-supported"},
{29,"service-request-denied"},
{30,"timeout"},
{31,"unknown-object"},
{32,"unknown-property"},
{33,"removed enumeration"},
{34,"unknown-vt-class"},
{35,"unknown-vt-session"},
{36,"unsupported-object-type"},
{37,"value-out-of-range"},
{38,"vt-session-already-closed"},
{39,"vt-session-termination-failure"},
{40,"write-access-denied"},
{41,"character-set-not-supported"},
{42,"invalid-array-index"},
{43,"cov-subscription-failed"},
{44,"not-cov-property"},
{45,"optional-functionaltity-not-supported"},
{46,"invalid-configuration-data"},
{47,"reserved by ASHRAE"},
{0, NULL}
};
static const value_string
BACnetPropertyIdentifier [] = {
{0,"acked-transition"},
{1,"ack-required"},
{2,"action"},
{3,"action-text"},
{4,"active-text"},
{5,"active-vt-session"},
{6,"alarm-value"},
{7,"alarm-values"},
{8,"all"},
{9,"all-write-successfull"},
{10,"apdu-segment-timeout"},
{11,"apdu-timeout"},
{12,"application-software-version"},
{13,"archive"},
{14,"bias"},
{15,"change-of-state-count"},
{16,"change-of-state-time"},
{17,"notification-class"},
{18,"the property in this place was deleted"},
{19,"controlled-variable-reference"},
{20,"controlled-variable-units"},
{21,"controlled-variable-value"},
{22,"cov-increment"},
{23,"datelist"},
{24,"daylights-savings-status"},
{25,"deadband"},
{26,"derivative-constant"},
{27,"derivative-constant-units"},
{28,"description"},
{29,"description-of-halt"},
{30,"device-address-binding"},
{31,"device-type"},
{32,"effective-period"},
{33,"elapsed-active-time"},
{34,"error-limit"},
{35,"event-enable"},
{36,"event-state"},
{37,"event-type"},
{38,"exception-schedule"},
{39,"fault-values"},
{40,"feedback-value"},
{41,"file-access-method"},
{42,"file-size"},
{43,"file-type"},
{44,"firmware-revision"},
{45,"high-limit"},
{46,"inactive-text"},
{47,"in-progress"},
{48,"instance-of"},
{49,"integral-constant"},
{50,"integral-constant-units"},
{51,"issue-confirmed-notifications"},
{52,"limit-enable"},
{53,"list-of-group-members"},
{54,"list-of-object-property-references"},
{55,"list-of-session-keys"},
{56,"local-date"},
{57,"local-time"},
{58,"location"},
{59,"low-limit"},
{60,"manipulated-variable-reference"},
{61,"maximum-output"},
{62,"max-apdu-length-accepted"},
{63,"max-info-frames"},
{64,"max-master"},
{65,"max-pres-value"},
{66,"minimum-off-time"},
{67,"minimum-on-time"},
{68,"minimum-output"},
{69,"min-pres-value"},
{70,"model-name"},
{71,"modification-date"},
{72,"notify-type"},
{73,"number-of-APDU-retries"},
{74,"number-of-states"},
{75,"object-identifier"},
{76,"object-list"},
{77,"object-name"},
{78,"object-property-reference"},
{79,"object-type"},
{80,"optional"},
{81,"out-of-service"},
{82,"output-units"},
{83,"event-parameters"},
{84,"polarity"},
{85,"present-value"},
{86,"priority"},
{87,"priority-array"},
{88,"priority-for-writing"},
{89,"process-identifier"},
{90,"program-change"},
{91,"program-location"},
{92,"program-state"},
{93,"proportional-constant"},
{94,"proportional-constant-units"},
{95,"protocol-conformance-class"},
{96,"protocol-object-types-supported"},
{97,"protocol-services-supported"},
{98,"protocol-version"},
{99,"read-only"},
{100,"reason-for-halt"},
{101,"recipient"},
{102,"recipient-list"},
{103,"reliability"},
{104,"relinquish-default"},
{105,"required"},
{106,"resolution"},
{107,"segmentation-supported"},
{108,"setpoint"},
{109,"setpoint-reference"},
{110,"state-text"},
{111,"status-flags"},
{112,"system-status"},
{113,"time-delay"},
{114,"time-of-active-time-reset"},
{115,"time-of-state-count-reset"},
{116,"time-synchronization-recipients"},
{117,"units"},
{118,"update-interval"},
{119,"utc-offset"},
{120,"vendor-identifier"},
{121,"vendor-name"},
{122,"vt-class-supported"},
{123,"weekly-schedule"},
{124,"attempted-samples"},
{125,"average-value"},
{126,"buffer-size"},
{127,"client-cov-increment"},
{128,"cov-resubscription-interval"},
{129,"current-notify-time"},
{130,"event-time-stamp"},
{131,"log-buffer"},
{132,"log-device-object-property"},
{133,"log-enable"},
{134,"log-interval"},
{135,"maximum-value"},
{136,"minimum-value"},
{137,"notification-threshold"},
{138,"previous-notify-time"},
{139,"protocol-revision"},
{140,"records-since-notification"},
{141,"record-count"},
{142,"start-time"},
{143,"stop-time"},
{144,"stop-when-full"},
{145,"total-record-count"},
{146,"valid-samples"},
{147,"window-interval"},
{148,"window-samples"},
{149,"maximum-value-time-stamp"},
{150,"minimum-value-time-stamp"},
{151,"variance-value"},
{152,"active-cov-subscriptions"},
{153,"backup-failure-timeout"},
{154,"configuration-files"},
{155,"database-revision"},
{156,"direct-reading"},
{157,"last-restore-time"},
{158,"maintenance-required"},
{159,"member-of"},
{160,"mode"},
{161,"operation-expected"},
{162,"setting"},
{163,"silenced"},
{164,"tracking-value"},
{165,"zone-members"},
{166,"life-safety-alarm-values"},
{167,"max-segments-accepted"},
{168,"profile-name"},
{0, NULL}
};
static const value_string
BACnetBinaryPV [] = {
{0,"inactive"},
{1,"active"},
{0,NULL}
};
static const value_string
BACnetCharacterSet [] = {
{0,"ANSI X3.4"},
{1,"IBM/Microsoft DBCS"},
{2,"JIS C 6226"},
{3,"ISO 10646(UCS-4)"},
{4,"ISO 10646(UCS-2)"},
{5,"ISO 18859-1"},
{0,NULL}
};
static const value_string
BACnetStatusFlags [] = {
{0,"in-alarm"},
{1,"fault"},
{2,"overridden"},
{3,"out-of-service"},
{0,NULL}
};
static const value_string
BACnetMessagePriority [] = {
{0,"normal"},
{1,"urgent"},
{0,NULL}
};
static const value_string
BACnetAcknowledgementFilter [] = {
{0,"and"},
{1,"or"},
{2,"all"},
{0,NULL}
};
static const value_string
BACnetResultFlags [] = {
{0,"firstitem"},
{1,"lastitem"},
{2,"moreitems"},
{0,NULL}
};
static const value_string
BACnetRelationSpecifier [] = {
{0,"equal"},
{1,"not-equal"},
{2,"less-than"},
{3,"greater-than"},
{4,"less-than-or-equal"},
{5,"greater-than-or-equal"},
{0,NULL}
};
static const value_string
BACnetSelectionLogic [] = {
{0,"normal"},
{1,"urgent"},
{0,NULL}
};
static const value_string
BACnetEventStateFilter [] = {
{0,"offnormal"},
{1,"fault"},
{2,"normal"},
{3,"all"},
{4,"active"},
{0,NULL}
};
static const value_string
BACnetEventTransitionBits [] = {
{0,"to-offnormal"},
{1,"to-fault"},
{2,"to-normal"},
{0,NULL}
};
static const value_string
BACnetSegmentation [] = {
{0,"segmented-both"},
{1,"segmented-transmit"},
{2,"segmented-receive"},
{3,"no-segmentation"},
{0,NULL}
};
static const value_string
BACnetSilencedState [] = {
{0,"unsilenced"},
{1,"audible-silenced"},
{2,"visible-silenced"},
{3,"all-silenced"},
{0,NULL}
};
static const value_string
BACnetDeviceStatus [] = {
{0,"operational"},
{1,"operational-read-only"},
{2,"download-required"},
{3,"download-in-progress"},
{4,"non-operational"},
{5,"backup-in-progress"},
{0,NULL}
};
static const value_string
BACnetEnableDisable [] = {
{0,"enable"},
{1,"disable"},
{0,NULL}
};
static const value_string
months [] = {
{1,"January" },
{2,"February" },
{3,"March" },
{4,"April" },
{5,"May" },
{6,"June" },
{7,"July" },
{8,"August" },
{9,"September" },
{10,"October" },
{11,"November" },
{12,"December" },
{255,"any month" },
{0,NULL }
};
static const value_string
weekofmonth [] = {
{1,"days numbered 1-7" },
{2,"days numbered 8-14" },
{3,"days numbered 15-21" },
{4,"days numbered 22-28" },
{5,"days numbered 29-31" },
{6,"last 7 days of this month" },
{255,"any week of this month" },
{0,NULL }
};
static const value_string
days [] = {
{1,"Monday" },
{2,"Tuesday" },
{3,"Wednesday" },
{4,"Thursday" },
{5,"Friday" },
{6,"Saturday" },
{7,"Sunday" },
{255,"any day of week" },
{0,NULL },
};
static const value_string
BACnetErrorClass [] = {
{0,"device" },
{1,"object" },
{2,"property" },
{3,"resources" },
{4,"security" },
{5,"services" },
{6,"vt" },
{0,NULL },
};
static const value_string
BACnetVTClass [] = {
{0,"default-terminal" },
{1,"ansi-x3-64" },
{2,"dec-vt52" },
{3,"dec-vt100" },
{4,"dec-vt200" },
{5,"hp-700-94" },
{6,"ibm-3130" },
{0,NULL },
};
static const value_string
BACnetEventType [] = {
{0,"change-of-bitstring" },
{1,"change-of-state" },
{2,"change-of-value" },
{3,"command-failure" },
{4,"floating-limit" },
{5,"out-of-range" },
{6,"complex-event-type" },
{7,"buffer-ready" },
{8,"change-of-life-safety" },
{0,NULL },
};
static const value_string
BACnetEventState [] = {
{0,"normal" },
{1,"fault" },
{2,"offnormal" },
{3,"high-limit" },
{4,"low-limit" },
{5,"life-safety-alarm" },
{0,NULL },
};
static const value_string
BACnetLogStatus [] = {
{0,"log-disabled" },
{1,"buffer-purged" },
{0,NULL },
};
static const value_string
BACnetMaintenance [] = {
{0,"none" },
{1,"periodic-test" },
{2,"need-service-operational" },
{3,"need-service-inoperative" },
{0,NULL },
};
static const value_string
BACnetNotifyType [] = {
{0,"alarm" },
{1,"event" },
{2,"ack-notification" },
{0,NULL },
};
static const value_string
BACnetServicesSupported [] = {
{0,"acknowledgeAlarm"},
{1,"confirmedCOVNotification"},
{2,"confirmedEventNotification"},
{3,"getAlarmSummary"},
{4,"getEnrollmentSummary"},
{5,"subscribeCOV"},
{6,"atomicReadFile"},
{7,"atomicWriteFile"},
{8,"addListElement"},
{9,"removeListElement"},
{10,"createObject"},
{11,"deleteObject"},
{12,"readProperty"},
{13,"readPropertyConditional"},
{14,"readPropertyMultiple"},
{15,"writeProperty"}, /* 15 */
{16,"writePropertyMultiple"},
{17,"deviceCommunicationControl"},
{18,"confirmedPrivateTransfer"},
{19,"confirmedTextMessage"},
{20,"reinitializeDevice"},
{21,"vtOpen"},
{22,"vtClose"},
{23,"vtData"},
{24,"authenticate"},
{25,"requestKey"}, /* 25 */
{26,"i-Am"},
{27,"i-Have"},
{28,"unconfirmedCOVNotification"},
{29,"unconfirmedEventNotification"},
{30,"unconfirmedPrivateTransfer"},
{31,"unconfirmedTextMessage"},
{32,"timeSynchronization"},
{33,"who-Has"},
{34,"who-Is"},
{35,"readRange"},
{36,"utcTimeSynchronization"},
{37,"lifeSafetyOperation"},
{38,"subscribeCOVProperty"},
{39,"getEventInformation"},
{40,"reserved by ASHRAE"},
{0, NULL}
};
static const value_string
BACnetPropertyStates [] = {
{0,"boolean-value"},
{1,"binary-value"},
{2,"event-type"},
{3,"polarity"},
{4,"program-change"},
{5,"program-state"},
{6,"reason-for-halt"},
{7,"reliability"},
{8,"state"},
{9,"system-status"},
{10,"units"},
{11,"unsigned-value"},
{12,"life-safety-mode"},
{13,"life-safety-state"},
{0,NULL}
};
static const value_string
BACnetProgramError [] = {
{0,"normal"},
{1,"load-failed"},
{2,"internal"},
{3,"program"},
{4,"other"},
{0,NULL}
};
static const value_string
BACnetProgramRequest [] = {
{0,"ready"},
{1,"load"},
{2,"run"},
{3,"halt"},
{4,"restart"},
{4,"unload"},
{0,NULL}
};
static const value_string
BACnetProgramState [] = {
{0,"idle"},
{1,"loading"},
{2,"running"},
{3,"waiting"},
{4,"halted"},
{4,"unloading"},
{0,NULL}
};
static const value_string
BACnetReinitializedStateOfDevice [] = {
{0,"coldstart"},
{1,"warmstart"},
{2,"startbackup"},
{3,"endbackup"},
{4,"startrestore"},
{5,"endrestore"},
{6,"abortrestore"},
{0,NULL}
};
static const value_string
BACnetPolarity [] = {
{0,"normal"},
{1,"reverse"},
{0,NULL}
};
static int proto_bacapp = -1;
static int hf_bacapp_type = -1;
static int hf_bacapp_SEG = -1;
static int hf_bacapp_MOR = -1;
static int hf_bacapp_SA = -1;
static int hf_bacapp_response_segments = -1;
static int hf_bacapp_max_adpu_size = -1;
static int hf_bacapp_invoke_id = -1;
static int hf_bacapp_objectType = -1;
static int hf_bacapp_instanceNumber = -1;
static int hf_bacapp_sequence_number = -1;
static int hf_bacapp_window_size = -1;
static int hf_bacapp_service = -1;
static int hf_bacapp_NAK = -1;
static int hf_bacapp_SRV = -1;
static int hf_BACnetRejectReason = -1;
static int hf_BACnetAbortReason = -1;
static int hf_BACnetTagNumber = -1;
static int hf_BACnetTagClass = -1;
static int hf_bacapp_tag_lvt = -1;
static int hf_bacapp_tag_ProcessId = -1;
static int hf_bacapp_tag_initiatingObjectType = -1;
static int hf_bacapp_vpart = -1;
static int hf_bacapp_uservice = -1;
static gint ett_bacapp = -1;
static gint ett_bacapp_control = -1;
static gint ett_bacapp_tag = -1;
static gint ett_bacapp_list = -1;
static gint ett_bacapp_value = -1;
static dissector_handle_t data_handle;
static gint32 propertyIdentifier = -1;
static guint8 bacapp_flags = 0;
static guint8 bacapp_seq = 0;
static guint
fTagNo (tvbuff_t *tvb, guint offset)
{
return (guint)(tvb_get_guint8(tvb, offset) >> 4);
}
static guint
fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* class_tag, guint32 *lvt)
{
guint8 tmp;
guint offs = 1;
tmp = tvb_get_guint8(tvb, offset);
*class_tag = tmp & 0x08; /* 0 = Application Tag, 1 = Context Specific Tag */
*lvt = tmp & 0x07;
*tag_no = tmp >> 4;
if (*tag_no == 15) { /* B'1111' because of extended tagnumber */
*tag_no = tvb_get_guint8(tvb, offset + offs++);
}
if (*lvt == 5) { /* length is more than 4 Bytes */
*lvt = tvb_get_guint8(tvb, offset + offs++);
if (*lvt == 254) { /* length is encoded with 16 Bits */
*lvt = tvb_get_guint8(tvb, offset + offs++);
*lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
} else {
if (*lvt == 255) { /* length is encoded with 32 Bits */
*lvt = tvb_get_guint8(tvb, offset + offs++);
*lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
*lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
*lvt = (*lvt << 8) + tvb_get_guint8(tvb, offset + offs++);
}
}
}
return offs;
}
static guint
fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
{
guint8 tmp;
guint64 val = 0;
guint8 tag_no, class_tag;
guint32 lvt, i;
guint offs;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
for (i = 0; i < min(lvt,8); i++) {
tmp = tvb_get_guint8(tvb, offset+offs+i);
val = (val << 8) + tmp;
}
proto_tree_add_text(tree, tvb, offset, min(lvt,8)+offs, "%s(Unsigned) %" PRIu64, LABEL(label), val);
return offset+offs+min(lvt,8);
}
static guint
fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
{
guint8 tmp;
guint64 val = 0;
guint8 tag_no, class_tag;
guint32 lvt, i;
guint offs;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
for (i = 0; i < min(lvt,8); i++) {
tmp = tvb_get_guint8(tvb, offset+offs+i);
val = (val << 8) + tmp;
}
proto_tree_add_text(tree, tvb, offset, min(lvt,8)+offs, "%s(Signed) %" PRId64, LABEL(label), (gint64) val);
return offset+offs+min(lvt,8);
}
static guint
fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint8 tmp;
guint32 val = 0, lvt, i;
guint8 tag_no, class_tag;
guint offs;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
for (i = 0; i < min(lvt, 4); i++) {
tmp = tvb_get_guint8(tvb, offset+offs+i);
val = (val << 8) + tmp;
}
proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, tvb, offset, offs+i, val);
return offset+offs+i;
}
static guint
fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
{
guint8 tmp;
guint val = 0;
guint32 lvt, i;
guint8 tag_no, class_tag;
guint offs;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
for (i = 0; i < min(lvt, 4); i++) {
tmp = tvb_get_guint8(tvb, offset+offs+i);
val = (val << 8) + tmp;
}
proto_tree_add_text(tree, tvb, offset, i+offs, "%s (hh.mm.ss): %d.%02d.%02d%s", LABEL(label), (val / 3600), ((val % 3600) / 60), (val % 60), val == 0 ? " (indefinite)" : "");
return offset+offs+i;
}
static guint
fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint32 month, weekOfMonth, dayOfWeek;
guint8 tag_no, class_tag;
guint32 lvt;
guint offs;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
month = tvb_get_guint8(tvb, offset+offs);
weekOfMonth = tvb_get_guint8(tvb, offset+offs+1);
dayOfWeek = tvb_get_guint8(tvb, offset+offs+2);
proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s %s, %s",
val_to_str(month, months, "month (%d) not found"),
val_to_str(weekOfMonth, weekofmonth, "week of month (%d) not found"),
val_to_str(dayOfWeek, days, "day of week (%d) not found"));
return offset+offs+lvt;
}
static guint
fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
{
guint32 year, month, day, weekday;
guint8 tag_no, class_tag;
guint32 lvt;
guint offs;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
year = tvb_get_guint8(tvb, offset+offs) + 1900;
month = tvb_get_guint8(tvb, offset+offs+1);
day = tvb_get_guint8(tvb, offset+offs+2);
weekday = tvb_get_guint8(tvb, offset+offs+3);
if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
proto_tree_add_text(tree, tvb, offset, lvt+offs, "%sany", LABEL(label));
else
proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%s %d, %d, (Day of Week = %s)",
LABEL(label), val_to_str(month, months, "month (%d) not found"),
day, year, val_to_str(weekday, days, "(%d) not found"));
return offset+offs+lvt;
}
static guint
fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
{
guint32 year, month, day, weekday, lvt;
guint8 tag_no, class_tag;
guint offs;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
year = tvb_get_guint8(tvb, offset+offs);
month = tvb_get_guint8(tvb, offset+offs+1);
day = tvb_get_guint8(tvb, offset+offs+2);
weekday = tvb_get_guint8(tvb, offset+offs+3);
if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
proto_tree_add_text(tree, tvb, offset, lvt+offs, "%sany", LABEL(label));
else
proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%d:%02d:%02d.%d %s = %02d:%02d:%02d.%d", LABEL(label), year > 12 ? year -12 : year, month, day, weekday, year > 12 ? "P.M." : "A.M.", year, month, day, weekday);
return offset+offs+lvt;
}
static guint
fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
{
proto_tree *subtree = tree;
proto_item *tt;
if (label != NULL) {
tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", LABEL(label));
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
}
offset = fDate (tvb,subtree,offset,"Date: ");
return fTime (tvb,subtree,offset,"Time: ");
}
static guint
fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag, but not for me */
return offset;
}
offset = fTime (tvb,tree,offset,"Time: ");
offset = fApplicationTypes (tvb,tree,offset, "Value: ", NULL);
}
return offset;
}
static guint
fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* Date */
offset = fDate (tvb, tree, offset, "Date: ");
break;
case 1: /* dateRange */
offset = fDateRange (tvb, tree, offset);
break;
case 2: /* BACnetWeekNDay */
offset = fWeekNDay (tvb, tree, offset);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset < tvb_reported_length(tvb)) { /* don't loop, it's a CHOICE */
switch (fTagNo(tvb, offset)) {
case 0: /* time */
offset = fTime (tvb, tree, offset, "timestamp: ");
break;
case 1: /* sequenceNumber */
offset = fUnsignedTag (tvb, tree, offset, "sequence Number: ");
break;
case 2: /* dateTime */
offset = fDateTime (tvb, tree, offset, "timestamp: ");
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* setpointReference */
offset = fObjectPropertyReference (tvb,tree,offset);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset < tvb_reported_length(tvb)) {
offset = fApplicationTypes (tvb,tree,offset, "increment: ",NULL);
}
return offset;
}
static guint
fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset < tvb_reported_length(tvb)) {
offset = fApplicationTypes (tvb,tree,offset, "valid Days: ", days);
offset = fTime (tvb,tree,offset,"from time: ");
offset = fTime (tvb,tree,offset,"to time: ");
offset = fRecipient (tvb,tree,offset);
offset = fProcessId (tvb,tree,offset);
offset = fApplicationTypes (tvb,tree,offset,"issue confirmed notifications: ", NULL);
offset = fApplicationTypes (tvb,tree,offset,"transitions: ", BACnetEventTransitionBits);
}
return offset;
}
static guint
fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, guint32 lvt)
{
guint8 *str_val;
guint len;
if ((lvt == 0) || ((lvt+offset) > tvb_length(tvb)))
lvt = tvb_length(tvb) - offset;
proto_tree_add_text(tree, tvb, offset, lvt, "[displayed OctetString with %d Bytes:] %s", lvt, LABEL(label));
do {
len = min (lvt, 200);
str_val = tvb_get_string(tvb, offset, len);
proto_tree_add_text(tree, tvb, offset, len, "%s", str_val);
g_free(str_val);
lvt -= len;
offset += len;
} while (lvt > 0);
if (tvb_length(tvb) < tvb_reported_length(tvb)) {
proto_tree_add_text(tree, tvb, offset, tvb_reported_length(tvb) - tvb_length(tvb), "[Frame is %d Bytes shorter than expected]", tvb_reported_length(tvb) - tvb_length(tvb));
str_val = tvb_get_string(tvb, offset, 1);
g_free(str_val);
}
return offset;
}
static guint
fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint8 tag_no, class_tag;
guint32 lvt;
guint offs;
offset = fUnsignedTag (tvb, tree, offset, "network-number");
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (lvt == 0) {
proto_tree_add_text(tree, tvb, offset, offs, "mac-address: broadcast");
offset += offs;
} else
offset = fOctetString (tvb, tree, offset, "mac-address: ", lvt);
return offset;
}
static guint
fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
offset = fOctetString (tvb,tree,offset,"session key: ", 8);
return fAddress (tvb,tree,offset);
}
static guint
fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint8 tag_no, class_tag;
guint32 lvt;
guint offs;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
proto_tree_add_item(tree, hf_bacapp_objectType, tvb, offset+offs, 4, FALSE);
proto_tree_add_item(tree, hf_bacapp_instanceNumber, tvb, offset+offs, 4, FALSE);
return offset+offs+4;
}
static guint
fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* device */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 1: /* address */
offset = fAddress (tvb, tree, offset);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* recipient */
offset = fRecipient (tvb, tree, offset);
break;
case 1: /* processId */
offset = fProcessId (tvb, tree, offset);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
offset = fObjectIdentifier (tvb, tree, offset);
return fAddress (tvb, tree, offset);
}
static guint
fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* deviceIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* objectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 2: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb,subtree,offset,&tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 3: /* propertyArrayIndex */
offset = fUnsignedTag (tvb,subtree,offset,"Property Array Index: ");
break;
case 4: /* propertyValue */
if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
case 5: /* priority */
offset = fUnsignedTag (tvb,subtree,offset,"Priority: ");
break;
case 6: /* quitOnFailure */
offset = fApplicationTypes (tvb,subtree,offset,"Quit On Failure: ",NULL);
break;
case 7: /* writeSuccessful */
offset = fApplicationTypes (tvb,subtree,offset,"Write Successful: ",NULL);
break;
default:
return offset;
}
}
return offset;
}
static guint
fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
return fActionCommand (tvb,tree,offset);
}
static guint
fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset, proto_item **tt)
{
guint8 tag_no, class_tag, tmp;
guint32 lvt, i;
guint offs;
propertyIdentifier = 0; /* global Variable */
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
for (i = 0; i < min(lvt,4); i++) {
tmp = tvb_get_guint8(tvb, offset+offs+i);
propertyIdentifier = (propertyIdentifier << 8) + tmp;
}
*tt = proto_tree_add_text(tree, tvb, offset, min(lvt,4)+offs,
"property Identifier: %s", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "(%d) reserved for ASHREA"));
return offset+offs+min(lvt,4);
}
static guint
fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
{
guint8 tag_no, class_tag, tmp;
guint32 lvt, l;
size_t inbytesleft, outbytesleft = 512;
guint offs;
guint8 *str_val;
guint8 bf_arr[512], *out = &bf_arr[0];
if (offset < tvb_reported_length(tvb)) {
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
tmp = tvb_get_guint8(tvb, offset+offs);
if (tmp == 3) {
proto_tree_add_text (tree, tvb, offset, 4+offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
offset+=4+offs;
lvt-=4;
}
if (tmp == 4) {
proto_tree_add_text (tree, tvb, offset, 1+offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
offset+=1+offs;
lvt-=1;
}
if ((tmp != 3) && (tmp != 4)) {
proto_tree_add_text (tree, tvb, offset, offs, "String Character Set: %s", val_to_str((guint) tmp, BACnetCharacterSet, "Reserved by ASHRAE"));
offset+=1+offs;
lvt--;
}
do {
l = inbytesleft = min(lvt, 255);
/*
* XXX - are we guaranteed that these encoding
* names correspond, on *all* platforms with
* iconv(), to the encodings we want?
* If not (and perhaps even if so), we should
* perhaps have our own iconv() implementation,
* with a different name, so that we control the
* encodings it supports and the names of those
* encodings.
*
* We should also handle that in the general
* string handling code, rather than making it
* specific to the BACAPP dissector, as many
* other dissectors need to handle various
* character encodings.
*/
str_val = tvb_get_string(tvb, offset, l);
/** this decoding may be not correct for multi-byte characters, Lka */
switch (tmp) {
case 0x00: /* ANSI_X3.4 */
fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ANSI_X3.4");
break;
case 1: /* IBM/MICROSOFT DBCS */
out = str_val;
break;
case 2: /* JIS C 6226 */
out = str_val;
break;
case 3: /* UCS-4 */
fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-4BE");
break;
case 4: /* UCS-2 */
fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-2BE");
break;
case 5: /* ISO8859-1 */
fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ISO8859-1");
break;
default:
out = str_val;
break;
}
proto_tree_add_text(tree, tvb, offset, l, "%s'%s'", LABEL(label), out);
g_free(str_val);
lvt-=l;
offset+=l;
} while (lvt > 0);
}
return offset;
}
static guint
fApplicationTypes (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label, const value_string *src)
{
guint8 tag_no, class_tag, tmp;
gint j, unused;
guint64 val = 0;
guint32 lvt, i;
guint offs;
gfloat f_val = 0.0;
gdouble d_val = 0.0;
guint8 bf_arr[256];
if (offset < tvb_reported_length(tvb)) {
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
switch (tag_no) {
case 0: /** NULL 20.2.2 */
proto_tree_add_text(tree, tvb, offset++, 1, "%sNULL", LABEL(label));
break;
case 1: /** BOOLEAN 20.2.3 */
proto_tree_add_text(tree, tvb, offset++, 1, "%s%s", LABEL(label), lvt == 0 ? "FALSE" : "TRUE");
break;
case 2: /** Unsigned Integer 20.2.4 */
offset = fUnsignedTag (tvb, tree, offset, label);
break;
case 3: /** Signed Integer 20.2.5 */
offset = fSignedTag (tvb, tree, offset, label);
break;
case 4: /** Real 20.2.6 */
f_val = tvb_get_ntohieee_float(tvb, offset+offs);
proto_tree_add_text(tree, tvb, offset, 4+offs, "%s%f (Real)", LABEL(label), f_val);
offset +=4+offs;
break;
case 5: /** Double 20.2.7 */
d_val = tvb_get_ntohieee_double(tvb, offset+offs);
proto_tree_add_text(tree, tvb, offset, 8+offs, "%s%lf (Double)", LABEL(label), d_val);
offset+=8+offs;
break;
case 6: /** Octet String 20.2.8 */
proto_tree_add_text(tree, tvb, offset, 1, "%s (%d Characters)", LABEL(label), lvt);
offset = fOctetString (tvb, tree, offset+offs, label, lvt);
break;
case 7: /** Character String 20.2.9 */
offset = fCharacterString (tvb,tree,offset,label);
break;
case 8: /** Bit String 20.2.10 */
offset+=offs;
unused = tvb_get_guint8(tvb, offset); /* get the unused Bits */
for (i = 0; i < (lvt-2); i++) {
tmp = tvb_get_guint8(tvb, (offset)+i+1);
for (j = 0; j < 8; j++) {
if (src != NULL) {
if (tmp & (1 << (7 - j)))
proto_tree_add_text(tree, tvb, offset+i+1, 1, "%s%s = TRUE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
else
proto_tree_add_text(tree, tvb, offset+i+1, 1, "%s%s = FALSE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
} else {
bf_arr[min(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
}
}
}
tmp = tvb_get_guint8(tvb, offset+lvt-1); /* now the last Byte */
if (src == NULL) {
for (j = 0; j < (8 - unused); j++)
bf_arr[min(255,((lvt-2)*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
for (; j < 8; j++)
bf_arr[min(255,((lvt-2)*8)+j)] = 'x';
bf_arr[min(255,((lvt-2)*8)+j)] = '\0';
proto_tree_add_text(tree, tvb, offset, lvt, "%sB'%s'", LABEL(label), bf_arr);
} else {
for (j = 0; j < (int) (8 - unused); j++) {
if (tmp & (1 << (7 - j)))
proto_tree_add_text(tree, tvb, offset+i+1, 1, "%s%s = TRUE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
else
proto_tree_add_text(tree, tvb, offset+i+1, 1, "%s%s = FALSE", LABEL(label), val_to_str((guint) (i*8 +j), src, "Reserved by ASHRAE"));
}
}
offset+=lvt;
break;
case 9: /** Enumerated 20.2.11 */
for (i = 0; i < min(lvt,8); i++) {
tmp = tvb_get_guint8(tvb, offset+offs+i);
val = (val << 8) + tmp;
}
if (src != NULL)
proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%s (%d)", LABEL(label), val_to_str((guint) val, src, "Reserved by ASHRAE"), (guint) val);
else
proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s%" PRIu64, LABEL(label), val);
offset+=lvt+offs;
break;
case 10: /** Date 20.2.12 */
offset = fDate (tvb, tree, offset, label);
break;
case 11: /** Time 20.2.13 */
offset = fTime (tvb, tree, offset, label);
break;
case 12: /** BACnetObjectIdentifier 20.2.14 */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 13: /* reserved for ASHRAE */
case 14:
case 15:
proto_tree_add_text(tree, tvb, offset, lvt+offs, "%s'reserved for ASHRAE'", LABEL(label));
offset+=lvt+offs;
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint8 tag_no, class_tag;
guint32 lvt;
guint offs, lastoffset = 0;
char ar[256];
sprintf (ar, "%s: ", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "identifier (%d) not found"));
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
offs = fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing tag, but not for me */
return offset;
}
/* Application Tags */
switch (propertyIdentifier) {
case 2: /* BACnetActionList */
offset = fActionList (tvb,tree,offset);
break;
case 30: /* BACnetAddressBinding */
offset = fAddressBinding (tvb,tree,offset);
break;
case 38: /* exception-schedule */
offset = fSpecialEvent (tvb,tree,offset);
break;
case 97: /* Protocol-Services-Supported */
offset = fApplicationTypes (tvb, tree, offset, ar, BACnetServicesSupported);
break;
case 111: /* Status-Flags */
case 112: /* System-Status */
offset = fApplicationTypes (tvb, tree, offset, ar, BACnetStatusFlags);
break;
case 117: /* units */
offset = fApplicationTypes (tvb, tree, offset, ar, BACnetUnits);
break;
case 76: /* object-list */
offset = fApplicationTypes (tvb, tree, offset, ar, NULL);
break;
case 87: /* priority-array */
offset = fPriorityArray (tvb, tree, offset);
break;
case 123: /* weekly-schedule */
offset = fWeeklySchedule (tvb,tree,offset);
break;
default:
offset = fApplicationTypes (tvb, tree, offset, ar, NULL);
break;
}
}
return offset;
}
static guint
fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
gboolean awaitingClosingTag = false;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (class_tag) {
if ((lvt == 7) && !awaitingClosingTag) { /* closing Tag */
return offset; /* but not for me */
}
if (lvt == 7) { /* closing Tag for me */
subtree = tree;
offset++;
awaitingClosingTag = false;
continue;
}
switch (tag_no) {
case 0: /* PropertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 1: /* propertyArrayIndex */
offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
break;
case 2: /* Value */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
awaitingClosingTag = true;
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
case 3: /* Priority */
offset = fSignedTag (tvb, subtree, offset, "Priority: ");
break;
default:
return offset;
break;
}
} else {
offset = fAbstractSyntaxNType (tvb,tree,offset);
}
}
return offset;
}
static guint
fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* ProcessId */
offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
break;
case 1: /* monitored ObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 2: /* issueConfirmedNotifications */
offset = fApplicationTypes (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
break;
case 3: /* life time */
offset = fTimeSpan (tvb,tree,offset,"life time");
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fCOVSubscription(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* Recipient */
offset = fRecipientProcess (tvb, tree, offset);
break;
case 1: /* monitoredPropertyReference */
offset = fPropertyReference (tvb, tree, offset);
break;
case 2: /* issueConfirmedNotifications */
offset = fApplicationTypes (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
break;
case 3: /* time remaining */
offset = fTimeSpan (tvb,tree,offset,"time remaining");
break;
case 4: /* COVIncrement */
offset = fApplicationTypes(tvb,tree,offset,"COV Increment: ", NULL);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* deviceInstanceLowLimit */
offset = fUnsignedTag (tvb, tree, offset, "device Instance Low Limit: ");
break;
case 1: /* deviceInstanceHighLimit */
offset = fUnsignedTag (tvb, tree, offset, "device Instance High Limit: ");
break;
case 2: /* BACnetObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 3: /* messageText */
offset = fCharacterString (tvb,tree,offset, "Object Name: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
offset++;
return offset;
}
switch (tag_no) {
case 0: /* day-schedule */
if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
offset = fTimeValue (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
guint i=1;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
offset++;
return offset;
}
tt = proto_tree_add_text(tree, tvb, offset, 0, val_to_str(i++, days, "day of week (%d) not found"));
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fDailySchedule (tvb,subtree,offset);
}
return offset;
}
static guint
fUTCTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset >= tvb_reported_length(tvb))
return offset;
return fDateTime (tvb, tree, offset, "UTC-Time: ");
}
static guint
fTimeSynchronizationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset >= tvb_reported_length(tvb))
return offset;
return fDateTime (tvb, tree, offset, NULL);
}
static guint
fDateRange (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset >= tvb_reported_length(tvb))
return offset;
offset = fDate (tvb,tree,offset,"Start Date: ");
return fDate (tvb, tree, offset, "End Date: ");
}
static guint
fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* textMessageSourceDevice */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 1: /* messageClass */
switch (fTagNo(tvb, offset)) {
case 0: /* numeric */
offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
break;
case 1: /* character */
offset = fApplicationTypes (tvb, tree, offset, "message Class: ", NULL);
break;
}
break;
case 2: /* messagePriority */
offset = fApplicationTypes (tvb, tree, offset, "Object Name: ", BACnetMessagePriority);
break;
case 3: /* message */
offset = fApplicationTypes (tvb, tree, offset, "message: ", NULL);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* textMessageSourceDevice */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 1: /* messageClass */
switch (fTagNo(tvb, offset)) {
case 0: /* numeric */
offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
break;
case 1: /* character */
offset = fApplicationTypes (tvb, tree, offset, "message Class: ", NULL);
break;
}
break;
case 2: /* messagePriority */
offset = fApplicationTypes (tvb, tree, offset, "Object Name: ", BACnetMessagePriority);
break;
case 3: /* message */
offset = fApplicationTypes (tvb, tree, offset, "message: ", NULL);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* vendorID */
offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
break;
case 1: /* serviceNumber */
offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
break;
case 2: /*serviceParameters */
if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* vendorID */
offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
break;
case 1: /* serviceNumber */
offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
break;
case 2: /*serviceParameters */
if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* vendorID */
offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
break;
case 1: /* serviceNumber */
offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
break;
case 2: /*serviceParameters */
if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
tt = proto_tree_add_text(subtree, tvb, offset, 1, "result Block");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 *label)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
if (label != NULL) {
tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", LABEL(label));
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
}
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
switch (tag_no) {
case 0: /* subscriberProcessId */
offset = fUnsignedTag (tvb, subtree, offset, "requesting Process Id: ");
break;
case 1: /* requestingSource */
offset = fApplicationTypes (tvb, subtree, offset, "requesting Source: ", NULL);
break;
case 2: /* request */
offset = fApplicationTypes (tvb, subtree, offset, "request: ", BACnetLifeSafetyOperation);
break;
case 3: /* objectId */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* change-of-bitstring */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fApplicationTypes (tvb, tree, offset, "referenced-bitstring: ", NULL);
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
break;
default:
return offset;
break;
}
}
break;
case 1: /* change-of-state */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fApplicationTypes (tvb, tree, offset, "new-state: ", BACnetPropertyStates);
case 1:
offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
break;
default:
return offset;
break;
}
}
break;
case 2: /* change-of-value */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: offset++;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fApplicationTypes (tvb, tree, offset, "changed-bits: ", NULL);
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "changed-value: ", NULL);
break;
default:
return offset;
break;
}
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
default:
return offset;
break;
}
}
break;
case 3: /* command-failure */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* "command-value: " */
offset = fAbstractSyntaxNType (tvb, tree, offset);
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
case 2: /* "feedback-value: " */
offset = fAbstractSyntaxNType (tvb, tree, offset);
default:
return offset;
break;
}
}
break;
case 4: /* floating-limit */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fApplicationTypes (tvb, tree, offset, "reference-value: ", NULL);
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "setpoint-value: ", NULL);
break;
case 3:
offset = fApplicationTypes (tvb, tree, offset, "error-limit: ", NULL);
default:
return offset;
break;
}
}
break;
case 5: /* out-of-range */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fApplicationTypes (tvb, tree, offset, "exceeding-value: ", NULL);
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "deadband: ", NULL);
break;
case 3:
offset = fApplicationTypes (tvb, tree, offset, "exceeded-limit: ", NULL);
default:
return offset;
break;
}
}
break;
case 6:
offset = fPropertyValue (tvb,tree,offset);
break;
case 7: /* buffer-ready */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fObjectIdentifier (tvb, tree, offset); /* buffer-device */
break;
case 1:
offset = fObjectIdentifier (tvb, tree, offset); /* buffer-object */
break;
case 2:
offset = fDateTime (tvb, tree, offset, "previous-notification: ");
break;
case 3:
offset = fDateTime (tvb, tree, offset, "current-notification: ");
default:
return offset;
break;
}
}
break;
case 8: /* change-of-life-safety */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fApplicationTypes (tvb, tree, offset, "new-state: ", BACnetLifeSafetyState);
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "new-mode: ", BACnetLifeSafetyState);
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "status-flags: ", BACnetStatusFlags);
case 3:
offset = fLifeSafetyOperationRequest(tvb, tree, offset, "operation-expected: ");
default:
return offset;
break;
}
}
break;
default:
return offset;
}
}
return offset;
}
static guint
fEventParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* change-of-bitstring */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fTimeSpan (tvb, tree, offset, "Time Delay");
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "bitmask: ", NULL);
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "bitstring value: ", BACnetEventTransitionBits);
break;
default:
return offset;
}
}
break;
case 1: /* change-of-state */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fTimeSpan (tvb, tree, offset, "Time Delay");
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "value: ", BACnetStatusFlags);
break;
default:
return offset;
}
}
break;
case 2: /* change-of-value */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fTimeSpan (tvb, tree, offset, "Time Delay");
break;
case 1: /* don't loop it, it's a CHOICE */
switch (fTagNo(tvb, offset)) {
case 0:
offset = fApplicationTypes (tvb, tree, offset, "bitmask: ", NULL);
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "referenced Property Incremental: ", NULL);
break;
default:
return offset;
}
default:
return offset;
}
}
break;
case 3: /* command-failure */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fTimeSpan (tvb, tree, offset, "Time Delay");
break;
case 1:
offset = fDeviceObjectPropertyReference (tvb,tree,offset);
default:
return offset;
}
}
break;
case 4: /* floating-limit */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fTimeSpan (tvb, tree, offset, "Time Delay");
break;
case 1:
offset = fDeviceObjectPropertyReference (tvb,tree,offset);
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "low diff limit: ", NULL);
break;
case 3:
offset = fApplicationTypes (tvb, tree, offset, "high diff limit: ", NULL);
break;
case 4:
offset = fApplicationTypes (tvb, tree, offset, "deadband: ", NULL);
break;
default:
return offset;
}
}
break;
case 5: /* out-of-range */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fTimeSpan (tvb, tree, offset, "Time Delay");
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "low limit: ", NULL);
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "high limit: ", NULL);
break;
case 3:
offset = fApplicationTypes (tvb, tree, offset, "deadband: ", NULL);
break;
default:
return offset;
}
}
break;
case 6:
offset = fPropertyValue (tvb,tree,offset);
break;
case 7: /* buffer-ready */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fUnsignedTag (tvb,tree,offset,"notification threshold");
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "previous notification count: ", NULL);
break;
default:
return offset;
}
}
break;
case 8: /* change-of-life-safety */
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0:
offset = fTimeSpan (tvb, tree, offset, "Time Delay");
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "life safety alarm value: ", BACnetLifeSafetyState);
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "alarm value: ", BACnetLifeSafetyState);
break;
case 3:
offset = fDeviceObjectPropertyReference (tvb, tree, offset);
break;
default:
return offset;
}
}
break;
default:
return offset;
}
}
return offset;
}
static guint
fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* timestamp */
offset = fDateTime (tvb,tree,offset,NULL);
break;
case 1: /* logDatum: don't loop, it's a CHOICE */
switch (fTagNo(tvb, offset)) {
case 0: /* logStatus */
offset = fApplicationTypes (tvb, tree, offset, "log status: ", BACnetLogStatus);
break;
case 1:
offset = fApplicationTypes (tvb, tree, offset, "boolean-value: ", NULL);
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "real value: ", NULL);
break;
case 3:
offset = fApplicationTypes (tvb, tree, offset, "enum value: ", NULL);
break;
case 4:
offset = fUnsignedTag (tvb, tree, offset, "unsigned value: ");
break;
case 5:
offset = fApplicationTypes (tvb, tree, offset, "signed value: ", NULL);
break;
case 6:
offset = fApplicationTypes (tvb, tree, offset, "bitstring value: ", NULL);
break;
case 7:
offset = fApplicationTypes (tvb, tree, offset, "null value: ", NULL);
break;
case 8:
offset = fError (tvb,tree,offset);
break;
case 9:
offset = fApplicationTypes (tvb, tree, offset, "time change: ", NULL);
break;
case 10: /* any Value */
offset = fAbstractSyntaxNType (tvb, tree, offset);
break;
default:
return offset;
}
break;
case 2:
offset = fApplicationTypes (tvb, tree, offset, "status Flags: ", BACnetStatusFlags);
break;
default:
return offset;
}
}
return offset;
}
static guint
fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* ProcessId */
offset = fProcessId (tvb,tree,offset);
break;
case 1: /* initiating ObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 2: /* event ObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 3: /* time stamp */
offset = fApplicationTypes (tvb, tree, offset, "Time Stamp: ", NULL);
break;
case 4: /* notificationClass */
offset = fApplicationTypes (tvb, tree, offset, "Notification Class: ", NULL);
break;
case 5: /* Priority */
offset = fApplicationTypes (tvb, tree, offset, "Priority: ", NULL);
break;
case 6: /* EventType */
offset = fApplicationTypes (tvb, tree, offset, "Event Type: ", BACnetEventType);
break;
case 7: /* messageText */
offset = fApplicationTypes (tvb, tree, offset, "message Text: ", NULL);
break;
case 8: /* NotifyType */
offset = fApplicationTypes (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
break;
case 9: /* ackRequired */
offset = fApplicationTypes (tvb, tree, offset, "ack Required: ", NULL);
break;
case 10: /* fromState */
offset = fApplicationTypes (tvb, tree, offset, "from State: ", BACnetEventState);
break;
case 11: /* toState */
offset = fApplicationTypes (tvb, tree, offset, "to State: ", BACnetEventState);
break;
case 12: /* NotificationParameters */
offset = fNotificationParameters (tvb, tree, offset);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* ProcessId */
offset = fProcessId (tvb,tree,offset);
break;
case 1: /* initiating ObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 2: /* event ObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 3: /* time stamp */
offset = fApplicationTypes (tvb, tree, offset, "Time Stamp: ", NULL);
break;
case 4: /* notificationClass */
offset = fApplicationTypes (tvb, tree, offset, "Notification Class: ", NULL);
break;
case 5: /* Priority */
offset = fApplicationTypes (tvb, tree, offset, "Priority: ", NULL);
break;
case 6: /* EventType */
offset = fApplicationTypes (tvb, tree, offset, "Event Type: ", BACnetEventType);
break;
case 7: /* messageText */
offset = fApplicationTypes (tvb, tree, offset, "message Text: ", NULL);
break;
case 8: /* NotifyType */
offset = fApplicationTypes (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
break;
case 9: /* ackRequired */
offset = fApplicationTypes (tvb, tree, offset, "ack Required: ", NULL);
break;
case 10: /* fromState */
offset = fApplicationTypes (tvb, tree, offset, "from State: ", BACnetEventState);
break;
case 11: /* toState */
offset = fApplicationTypes (tvb, tree, offset, "to State: ", BACnetEventState);
break;
case 12: /* NotificationParameters */
offset = fNotificationParameters (tvb, tree, offset);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* ProcessId */
offset = fProcessId (tvb,tree,offset);
break;
case 1: /* initiating ObjectId */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 2: /* monitored ObjectId */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 3: /* time remaining */
offset = fTimeSpan (tvb, tree, offset, "Time remaining");
break;
case 4: /* List of Values */
if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fPropertyValue (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* subscriberProcessId */
offset = fProcessId (tvb,tree,offset);
break;
case 1: /* initiating ObjectId */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 2: /* monitored ObjectId */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 3: /* time remaining */
offset = fTimeSpan (tvb, tree, offset, "Time remaining");
break;
case 4: /* List of Values */
if (((lvt == 6) && class_tag)) { offset++; /* opening Tag */
tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fPropertyValue (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fAcknowlegdeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* acknowledgingProcessId */
offset = fUnsignedTag (tvb, tree, offset, "acknowledging Process Id: ");
break;
case 1: /* eventObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 2: /* eventStateAcknowledged */
fApplicationTypes (tvb, tree, offset, "event State Acknowledged: ", BACnetEventState);
break;
case 3: /* timeStamp */
offset = fTime (tvb, tree, offset, "time Stamp: ");
break;
case 4: /* acknowledgementSource */
offset = fApplicationTypes (tvb, tree, offset, "acknowledgement Source: ", NULL);
break;
case 5: /* timeOfAcknowledgement */
offset = fTime (tvb, tree, offset, "time Of Acknowledgement: ");
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fGetAlarmSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
offset = fObjectIdentifier (tvb, tree, offset);
offset = fApplicationTypes (tvb, tree, offset, "alarm State: ", BACnetEventState);
offset = fApplicationTypes (tvb, tree, offset, "acknowledged Transitions: ", BACnetEventTransitionBits);
}
return offset;
}
static guint
fGetEnrollmentSummaryRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* acknowledgmentFilter */
offset = fApplicationTypes (tvb, tree, offset, "acknowledgment Filter: ", BACnetAcknowledgementFilter);
break;
case 1: /* eventObjectId */
offset = fRecipientProcess (tvb, tree, offset);
break;
case 2: /* eventStateFilter */
offset = fApplicationTypes (tvb, tree, offset, "event State Filter: ", BACnetEventStateFilter);
break;
case 3: /* eventTypeFilter */
offset = fApplicationTypes (tvb, tree, offset, "event Type Filter: ", BACnetEventType);
break;
case 4: /* priorityFilter */
offset = fUnsignedTag (tvb, tree, offset, "min Priority: ");
offset = fUnsignedTag (tvb, tree, offset, "max Priority: ");
break;
case 5: /* notificationClassFilter */
offset = fUnsignedTag (tvb, tree, offset, "notification Class Filter: ");
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fGetEnrollmentSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
offset = fObjectIdentifier (tvb, tree, offset);
offset = fApplicationTypes (tvb, tree, offset, "event Type: ", BACnetEventType);
offset = fApplicationTypes (tvb, tree, offset, "event State: ", BACnetEventStateFilter);
offset = fUnsignedTag (tvb, tree, offset, "Priority: ");
offset = fUnsignedTag (tvb, tree, offset, "notification Class: ");
}
return offset;
}
static guint
fGetEventInformationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* lastReceivedObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
flistOfEventSummaries (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* ObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 1: /* eventState */
offset = fApplicationTypes (tvb, tree, offset, "event State: ", BACnetEventStateFilter);
break;
case 2: /* acknowledgedTransitions */
offset = fApplicationTypes (tvb, tree, offset, "acknowledged Transitions: ", BACnetEventTransitionBits);
break;
case 3: /* eventTimeStamps */
offset = fTime (tvb, tree, offset, "time Stamp: ");
offset = fTime (tvb, tree, offset, "time Stamp: ");
offset = fTime (tvb, tree, offset, "time Stamp: ");
break;
case 4: /* notifyType */
offset = fApplicationTypes (tvb, tree, offset, "Notify Type: ", BACnetNotifyType);
break;
case 5: /* eventEnable */
offset = fApplicationTypes (tvb, tree, offset, "event Enable: ", BACnetEventTransitionBits);
break;
case 6: /* eventPriorities */
offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fGetEventInformationACK (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* listOfEventSummaries */
offset = flistOfEventSummaries (tvb, tree, offset);
break;
case 1: /* moreEvents */
offset = fApplicationTypes (tvb, tree, offset, "more Events: ", NULL);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fAddListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* ObjectId */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 2: /* propertyArrayIndex */
offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
break;
case 3: /* listOfElements */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fDeleteObjectRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
return fObjectIdentifier (tvb, tree, offset);
}
static guint
fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* timeDuration */
offset = fUnsignedTag (tvb,tree,offset,"time Duration: ");
break;
case 1: /* enable-disable */
offset = fApplicationTypes (tvb, tree, offset, "enable-disable: ", BACnetEnableDisable);
break;
case 2: /* password */
offset = fApplicationTypes (tvb, tree, offset, "Password: ", NULL);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* reinitializedStateOfDevice */
offset = fApplicationTypes (tvb, tree, offset, "reinitialized State Of Device: ", BACnetReinitializedStateOfDevice);
break;
case 1: /* password */
offset = fApplicationTypes (tvb, tree, offset, "Password: ", NULL);
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fVtOpenRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset >= tvb_reported_length(tvb))
return offset;
offset = fApplicationTypes (tvb, tree, offset, "vtClass: ", BACnetVTClass);
return fUnsignedTag (tvb,tree,offset,"local VT Session ID: ");
}
static guint
fVtOpenAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset >= tvb_reported_length(tvb))
return offset;
return offset= fUnsignedTag (tvb,tree,offset,"remote VT Session ID: ");
}
static guint
fVtCloseRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
offset= fUnsignedTag (tvb,tree,offset,"remote VT Session ID: ");
}
return offset;
}
static guint
fVtDataRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset >= tvb_reported_length(tvb))
return offset;
offset= fUnsignedTag (tvb,tree,offset,"VT Session ID: ");
offset = fApplicationTypes (tvb, tree, offset, "VT New Data: ", NULL);
return fUnsignedTag (tvb,tree,offset,"VT Data Flag: ");;
}
static guint
fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* BOOLEAN */
offset = fApplicationTypes (tvb, tree, offset, "all New Data Accepted: ", NULL);
break;
case 1: /* Unsigned OPTIONAL */
offset = fUnsignedTag (tvb, tree, offset, "accepted Octet Count: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* Unsigned32 */
offset = fUnsignedTag (tvb, tree, offset, "pseudo Random Number: ");
break;
case 1: /* expected Invoke ID Unsigned8 OPTIONAL */
proto_tree_add_item(tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
break;
case 2: /* Chararacter String OPTIONAL */
offset = fApplicationTypes (tvb, tree, offset, "operator Name: ", NULL);
break;
case 3: /* Chararacter String OPTIONAL */
offset = fApplicationTypes (tvb, tree, offset, "operator Password: ", NULL);
break;
case 4: /* Boolean OPTIONAL */
offset = fApplicationTypes (tvb, tree, offset, "start Encyphered Session: ", NULL);
break;
default:
return offset;
}
}
return offset;
}
static guint
fAuthenticateAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
return fUnsignedTag (tvb, tree, offset, "modified Random Number: ");
}
static guint
fRequestKeyRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
offset = fObjectIdentifier (tvb, tree, offset); /* Requesting Device Identifier */
offset = fAddress (tvb, tree, offset);
offset = fObjectIdentifier (tvb, tree, offset); /* Remote Device Identifier */
return fAddress (tvb, tree, offset);
}
static guint
fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* subscriberProcessId */
offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
break;
case 1: /* monitored ObjectId */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 2: /* issueConfirmedNotifications */
offset = fApplicationTypes (tvb, tree, offset, "issue Confirmed Notifications: ", NULL);
break;
case 3: /* life time */
offset = fTimeSpan (tvb,tree,offset,"life time");
break;
case 4: /* monitoredPropertyIdentifier */
offset = fApplicationTypes (tvb, tree, offset, "monitored Property Id: ", NULL);
break;
case 5: /* covIncrement */
offset = fUnsignedTag (tvb, tree, offset, "cov Increment: ");
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fRemoveListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* ObjectId */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 2: /* propertyArrayIndex */
offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
break;
case 3: /* listOfElements */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fReadPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* objectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
break;
case 2: /* propertyArrayIndex */
offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fReadPropertyAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) {
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 2: /* propertyArrayIndex */
offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
break;
case 3: /* propertyValue */
if ((lvt == 6) && class_tag) { offset++;
offset = fAbstractSyntaxNType (tvb, subtree, offset);
/* offset = fPropertyValue (tvb,subtree,offset); */
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fWritePropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) {
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
break;
case 2: /* propertyArrayIndex */
offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
break;
case 3: /* propertyValue */
if ((lvt == 6) && class_tag) { offset++;
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
case 4: /* Priority (only used for write) */
offset = fSignedTag (tvb, subtree, offset, "Priority: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* listOfPropertyValues */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fPropertyValue (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fWritePropertyMultipleRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset >= tvb_reported_length(tvb))
return offset;
return fWriteAccessSpecification (tvb, tree, offset);
}
static guint
fPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree* subtree = tree;
proto_item* tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag, but not for me */
return offset;
}
switch (tag_no) {
case 0: /* PropertyIdentifier */
offset = fPropertyIdentifier (tvb, tree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 1: /* propertyArrayIndex */
offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
proto_tree* subtree = tree;
proto_item* tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* ObjectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* PropertyIdentifier */
offset = fPropertyIdentifier (tvb, tree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 2: /* propertyArrayIndex */
offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree* subtree = tree;
proto_item* tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++; /* check it again, Lka */
continue;
}
switch (tag_no) {
case 0: /* ObjectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* PropertyIdentifier */
offset = fPropertyIdentifier (tvb, tree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 2: /* propertyArrayIndex */
offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
break;
case 3: /* Value */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
case 4: /* Priority */
offset = fSignedTag (tvb, subtree, offset, "Priority: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fDeviceObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
proto_tree* subtree = tree;
proto_item* tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* ObjectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* PropertyIdentifier */
offset = fPropertyIdentifier (tvb, tree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 2: /* propertyArrayIndex */
offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
break;
case 3: /* deviceIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
default:
return offset;
}
}
return offset;
}
static guint
fPriorityArray (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint8 i, ar[256];
if (offset >= tvb_reported_length(tvb))
return offset;
for (i = 1; i <= 16; i++) {
sprintf (ar, "%s[%d]: ", val_to_str(propertyIdentifier, BACnetPropertyIdentifier, "identifier (%d) not found"), i);
offset = fApplicationTypes (tvb, tree, offset, ar, BACnetBinaryPV);
}
return offset;
}
static guint
fDeviceObjectReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* deviceIdentifier */
offset = fObjectIdentifier (tvb, tree, offset);
break;
case 1: /* ObjectIdentifier */
offset = fObjectIdentifier (tvb, tree, offset);
break;
default:
return offset;
}
}
return offset;
}
static guint
fSpecialEvent (tvbuff_t *tvb, proto_tree *subtree, guint offset)
{
guint8 tag_no, class_tag;
guint32 lvt;
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
continue;
}
switch (fTagNo(tvb,offset)) {
case 0: /* calendaryEntry */
offset = fCalendaryEntry (tvb, subtree, offset);
break;
case 1: /* calendarReference */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 2: /* calendarReference */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fTimeValue (tvb, subtree, offset);
break;
}
FAULT;
break;
case 3: /* eventPriority */
offset = fUnsignedTag (tvb, subtree, offset, "event priority: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fSelectionCriteria (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb,offset)) {
case 0: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, tree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 1: /* propertyArrayIndex */
offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
break;
case 2: /* relationSpecifier */
offset = fApplicationTypes (tvb, subtree, offset, "relation Specifier: ", BACnetRelationSpecifier);
break;
case 3: /* comparisonValue */
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
default:
return offset;
}
}
return offset;
}
static guint
fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
continue;
}
switch (tag_no) {
case 0: /* selectionLogic */
offset = fApplicationTypes (tvb, subtree, offset, "selection Logic: ", BACnetSelectionLogic);
break;
case 1: /* listOfSelectionCriteria */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fSelectionCriteria (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fReadPropertyConditionalRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectSelectionCriteria */
offset = fObjectSelectionCriteria (tvb, subtree, offset);
break;
case 1: /* listOfPropertyReferences */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fPropertyReference (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fReadAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectIdentifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* listOfPropertyReferences */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fPropertyReference (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no;
guint8 class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectSpecifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* list of Results */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
break;
}
FAULT;
break;
case 2: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_list);
break;
case 3: /* propertyArrayIndex Optional */
offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
break;
case 4: /* propertyValue */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
case 5: /* propertyAccessError */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
/* Error Code follows */
offset = fApplicationTypes (tvb, subtree, offset, "error Class: ", BACnetErrorClass);
offset = fApplicationTypes (tvb, subtree, offset, "error Code: ", BACnetErrorCode);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fReadPropertyConditionalAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
/* listOfReadAccessResults */
return fReadAccessResult (tvb, tree, offset);
}
static guint
fObjectSpecifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* objectType */
proto_tree_add_item(tree, hf_bacapp_tag_initiatingObjectType, tvb, offset++, 1, TRUE);
break;
case 1: /* objectIdentifier */
offset = fObjectIdentifier (tvb, tree, offset);
break;
default:
return offset;
}
}
return offset;
}
static guint
fCreateObjectRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
while ((offset < tvb_reported_length(tvb)) && (offset > lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectSpecifier */
offset = fObjectSpecifier (tvb, subtree, offset);
break;
case 1: /* propertyValue */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fPropertyValue (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
return fObjectIdentifier (tvb, tree, offset);
}
static guint
fReadRangeRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectSpecifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 2: /* propertyArrayIndex Optional */
offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
break;
case 3: /* range byPosition */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fApplicationTypes (tvb, subtree, offset, "reference Index: ", NULL);
offset = fApplicationTypes (tvb, subtree, offset, "reference Count: ", NULL);
break;
}
FAULT;
break;
case 4: /* range byTime */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fApplicationTypes (tvb, subtree, offset, "reference Time: ", NULL);
offset = fApplicationTypes (tvb, subtree, offset, "reference Count: ", NULL);
break;
}
FAULT;
break;
case 5: /* range timeRange */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fApplicationTypes (tvb, subtree, offset, "beginning Time: ", NULL);
offset = fApplicationTypes (tvb, subtree, offset, "ending Time: ", NULL);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fReadRangeAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
subtree = tree;
offset++;
continue;
}
switch (tag_no) {
case 0: /* objectSpecifier */
offset = fObjectIdentifier (tvb, subtree, offset);
break;
case 1: /* propertyIdentifier */
offset = fPropertyIdentifier (tvb, subtree, offset, &tt);
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
break;
case 2: /* propertyArrayIndex Optional */
offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
break;
case 3: /* resultFlags */
offset = fApplicationTypes (tvb, subtree, offset, "result Flags: ", BACnetResultFlags);
break;
case 4: /* itemCount */
offset = fUnsignedTag (tvb, subtree, offset, "item Count: ");
break;
case 5: /* itemData */
if ((lvt == 6) && class_tag) { offset++; /* opening Tag */
offset = fAbstractSyntaxNType (tvb, subtree, offset);
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fAtomicReadFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
offset = fObjectIdentifier (tvb, tree, offset);
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
subtree = tree;
continue;
}
switch (tag_no) {
case 0: /* streamAccess */
if ((lvt == 6) && class_tag) { /* opening Tag */
tt = proto_tree_add_text(subtree, tvb, offset++, 1, "stream Access");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
offset = fUnsignedTag (tvb, subtree, offset, "requestet Octet Count: ");
break;
}
FAULT;
break;
case 1: /* recordAccess */
if ((lvt == 6) && class_tag) { /* opening Tag */
tt = proto_tree_add_text(subtree, tvb, offset++, 1, "record Access");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fSignedTag (tvb, subtree, offset, "File Start Record: ");
offset = fUnsignedTag (tvb, subtree, offset, "requestet Record Count: ");
break;
}
FAULT;
break;
default:
return offset;
}
}
return offset;
}
static guint
fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) { /* Segment of an Request */
if (bacapp_flags & 0x04) { /* More Flag is set */
offset = fOctetString (tvb, tree, offset, "file Data: ", 0);
} else {
offset = fOctetString (tvb, tree, offset, "file Data: ", tvb_reported_length(tvb) - offset - 1);
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
}
}
} else {
offset = fObjectIdentifier (tvb, tree, offset); /* file Identifier */
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
switch (tag_no) {
case 0: /* streamAccess */
if ((lvt == 6) && class_tag) { /* opening Tag */
tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
offset = fApplicationTypes (tvb, subtree, offset, "file Data: ", NULL);
}
if (bacapp_flags && 0x04) { /* More Flag is set */
break;
}
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
offset++;
subtree = tree;
}
break;
case 1: /* recordAccess */
if ((lvt == 6) && class_tag) { /* opening Tag */
tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fSignedTag (tvb, subtree, offset, "file Start Record: ");
offset = fUnsignedTag (tvb, subtree, offset, "Record Count: ");
offset = fApplicationTypes (tvb, subtree, offset, "file Data: ", NULL);
}
if (bacapp_flags && 0x04) { /* More Flag is set */
break;
}
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if (((lvt == 7) && class_tag)) { /* closing Tag */
offset++;
subtree = tree;
}
break;
default:
return offset;
}
}
return offset;
}
static guint
fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
switch (fTagNo(tvb, offset)) {
case 0: /* streamAccess */
offset = fSignedTag (tvb, tree, offset, "File Start Position: ");
break;
case 1: /* recordAccess */
offset = fSignedTag (tvb, tree, offset, "File Start Record: ");
break;
default:
return offset;
}
return offset;
}
static guint
fAtomicReadFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint8 tag_no, class_tag;
guint32 lvt;
proto_tree *subtree = tree;
proto_item *tt;
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((bacapp_flags & 0x08) && (bacapp_seq != 0)) { /* Segment of an Request */
if (bacapp_flags & 0x04) { /* More Flag is set */
offset = fOctetString (tvb, tree, offset, "File Data: ", 0);
} else {
offset = fOctetString (tvb, tree, offset, "File Data: ", tvb_reported_length(tvb)-offset-1);
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
}
}
} else {
offset = fApplicationTypes (tvb, subtree, offset, "End Of File: ", NULL);
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
switch (tag_no) {
case 0: /* streamAccess */
if ((lvt == 6) && class_tag) { /* opening Tag */
tt = proto_tree_add_text(tree, tvb, offset++, 1, "stream Access");
subtree = proto_item_add_subtree(tt, ett_bacapp_value);
offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
offset = fApplicationTypes (tvb, subtree, offset, "file Data: ", NULL);
}
if (bacapp_flags && 0x04) { /* More Flag is set */
break;
}
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
subtree = tree;
}
break;
case 1: /* recordAccess */
if ((lvt == 6) && class_tag) { /* opening Tag */
proto_tree_add_text(tree, tvb, offset++, 1, "stream Access {");
offset = fSignedTag (tvb, subtree, offset, "File Start Record: ");
offset = fUnsignedTag (tvb, subtree, offset, "returned Record Count: ");
offset = fApplicationTypes (tvb, subtree, offset, "Data: ", NULL);
}
if (bacapp_flags && 0x04) { /* More Flag is set */
break;
}
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
if ((lvt == 7) && class_tag) { /* closing Tag */
offset++;
subtree = tree;
}
break;
default:
return offset;
}
}
return offset;
}
static guint
fReadPropertyMultipleRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
{
return fReadAccessSpecification (tvb,subtree,offset);
}
static guint
fReadPropertyMultipleAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
return fReadAccessResult (tvb,tree,offset);
}
static guint
fConfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
{
if (offset >= tvb_reported_length(tvb))
return offset;
switch (service_choice) {
case 0: /* acknowledgeAlarm */
offset = fAcknowlegdeAlarmRequest (tvb, tree, offset);
break;
case 1: /* confirmedCOVNotification */
offset = fConfirmedCOVNotificationRequest (tvb, tree, offset);
break;
case 2: /* confirmedEventNotification */
offset = fConfirmedEventNotificationRequest (tvb, tree, offset);
break;
case 3: /* confirmedGetAlarmSummary conveys no parameters */
break;
case 4: /* getEnrollmentSummaryRequest */
offset = fGetEnrollmentSummaryRequest (tvb, tree, offset);
break;
case 5: /* subscribeCOVRequest */
offset = fSubscribeCOVRequest(tvb, tree, offset);
break;
case 6: /* atomicReadFile-Request */
offset = fAtomicReadFileRequest(tvb, tree, offset);
break;
case 7: /* atomicWriteFile-Request */
offset = fAtomicWriteFileRequest(tvb, tree, offset);
break;
case 8: /* AddListElement-Request */
offset = fAddListElementRequest(tvb, tree, offset);
break;
case 9: /* removeListElement-Request */
offset = fRemoveListElementRequest(tvb, tree, offset);
break;
case 10: /* createObjectRequest */
offset = fCreateObjectRequest(tvb, tree, offset);
break;
case 11: /* deleteObject */
offset = fDeleteObjectRequest(tvb, tree, offset);
break;
case 12:
offset = fReadPropertyRequest(tvb, tree, offset);
break;
case 13:
offset = fReadPropertyConditionalRequest(tvb, tree, offset);
break;
case 14:
offset = fReadPropertyMultipleRequest(tvb, tree, offset);
break;
case 15:
offset = fWritePropertyRequest(tvb, tree, offset);
break;
case 16:
offset = fWritePropertyMultipleRequest(tvb, tree, offset);
break;
case 17:
offset = fDeviceCommunicationControlRequest(tvb, tree, offset);
break;
case 18:
offset = fConfirmedPrivateTransferRequest(tvb, tree, offset);
break;
case 19:
offset = fConfirmedTextMessageRequest(tvb, tree, offset);
break;
case 20:
offset = fReinitializeDeviceRequest(tvb, tree, offset);
break;
case 21:
offset = fVtOpenRequest(tvb, tree, offset);
break;
case 22:
offset = fVtCloseRequest (tvb, tree, offset);
break;
case 23:
offset = fVtDataRequest (tvb, tree, offset);
break;
case 24:
offset = fAuthenticateRequest (tvb, tree, offset);
break;
case 25:
offset = fRequestKeyRequest (tvb, tree, offset);
break;
case 26:
offset = fReadRangeRequest (tvb, tree, offset);
break;
case 27:
offset = fLifeSafetyOperationRequest(tvb, tree, offset, NULL);
break;
case 28:
offset = fSubscribeCOVPropertyRequest(tvb, tree, offset);
break;
case 29:
offset = fGetEventInformationRequest (tvb, tree, offset);
break;
default:
return offset;
break;
}
return offset;
}
static guint
fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
{
if (offset >= tvb_reported_length(tvb))
return offset;
switch (service_choice) {
case 3: /* confirmedEventNotificationAck */
offset = fGetAlarmSummaryAck (tvb, tree, offset);
break;
case 4: /* getEnrollmentSummaryAck */
offset = fGetEnrollmentSummaryAck (tvb, tree, offset);
break;
case 6: /* atomicReadFile */
offset = fAtomicReadFileAck (tvb, tree, offset);
break;
case 7: /* atomicReadFileAck */
offset = fAtomicWriteFileAck (tvb, tree, offset);
break;
case 10: /* createObject */
offset = fCreateObjectAck (tvb, tree, offset);
break;
case 12:
offset = fReadPropertyAck (tvb, tree, offset);
break;
case 13:
offset = fReadPropertyConditionalAck (tvb, tree, offset);
break;
case 14:
offset = fReadPropertyMultipleAck (tvb, tree, offset);
break;
case 18:
offset = fConfirmedPrivateTransferAck(tvb, tree, offset);
break;
case 21:
offset = fVtOpenAck (tvb, tree, offset);
break;
case 23:
offset = fVtDataAck (tvb, tree, offset);
break;
case 24:
offset = fAuthenticateAck (tvb, tree, offset);
break;
case 26:
offset = fReadRangeAck (tvb, tree, offset);
break;
case 29:
offset = fGetEventInformationACK (tvb, tree, offset);
break;
default:
return offset;
}
return offset;
}
static guint
fIAmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint8 tmp, tag_no, class_tag;
guint32 lvt, val = 0, i;
/* BACnetObjectIdentifier */
offset = fApplicationTypes (tvb, tree, offset, "BACnet Object Identifier: ", NULL);
/* MaxAPDULengthAccepted */
offset = fApplicationTypes (tvb, tree, offset, "Maximum ADPU Length accepted: ", NULL);
/* segmentationSupported */
fTagHeader (tvb, offset, &tag_no, &class_tag, &lvt);
offset++; /* set offset according to enhancements.... */
for (i = 0; i < min(lvt, 4); i++) {
tmp = tvb_get_guint8(tvb, offset+i);
val = (val << 8) + tmp;
}
proto_tree_add_text(tree, tvb, offset, 1, "segmentation Supported: %s", val_to_str(val, BACnetSegmentation, "segmentation (%d) not found"));
offset+=lvt;
/* vendor ID */
return fUnsignedTag (tvb, tree, offset, "vendor ID: ");
}
static guint
fIHaveRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
/* BACnetDeviceIdentifier */
offset = fApplicationTypes (tvb, tree, offset, "Device Identifier: ", NULL);
/* BACnetObjectIdentifier */
offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: ", NULL);
/* ObjectName */
return fApplicationTypes (tvb, tree, offset, "Object Name: ", NULL);
}
static guint
fWhoIsRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* DeviceInstanceRangeLowLimit Optional */
offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range Low Limit: ");
break;
case 1: /* DeviceInstanceRangeHighLimit Optional but required if DeviceInstanceRangeLowLimit is there */
offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range High Limit: ");
break;
default:
return offset;
break;
}
}
return offset;
}
static guint
fUnconfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
{
if (offset >= tvb_reported_length(tvb))
return offset;
switch (service_choice) {
case 0: /* I-Am-Request */
offset = fIAmRequest (tvb, tree, offset);
break;
case 1: /* i-Have Request */
offset = fIHaveRequest (tvb, tree, offset);
break;
case 2: /* unconfirmedCOVNotification */
offset = fUnconfirmedCOVNotificationRequest (tvb, tree, offset);
break;
case 3: /* unconfirmedEventNotification */
offset = fUnconfirmedEventNotificationRequest (tvb, tree, offset);
break;
case 4: /* unconfirmedPrivateTransfer */
offset = fUnconfirmedPrivateTransferRequest(tvb, tree, offset);
break;
case 5: /* unconfirmedTextMessage */
offset = fUnconfirmedTextMessageRequest(tvb, tree, offset);
break;
case 6: /* timeSynchronization */
offset = fTimeSynchronizationRequest (tvb, tree, offset);
break;
case 7: /* who-Has */
offset = fWhoHas (tvb, tree, offset);
break;
case 8: /* who-Is */
offset = fWhoIsRequest (tvb, tree, offset);
break;
case 9: /* utcTimeSynchronization */
offset = fUTCTimeSynchronizationRequest (tvb, tree, offset);
break;
default:
break;
}
return offset;
}
static guint
fConfirmedRequestPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
{ /* BACnet-Confirmed-Request */
/* ASHRAE 135-2001 20.1.2 */
proto_item *tc, *tt, *ti;
proto_tree *bacapp_tree, *bacapp_tree_control, *bacapp_tree_tag;
gint tmp, bacapp_type, service_choice;
tmp = (gint) tvb_get_guint8(tvb, offset);
bacapp_type = (tmp >> 4) & 0x0f;
bacapp_flags = tmp & 0x0f;
service_choice = (gint) tvb_get_guint8(tvb, offset+3);
if (bacapp_flags & 0x08)
service_choice = (gint) tvb_get_guint8(tvb, offset+5);
ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
proto_tree_add_item(bacapp_tree_control, hf_bacapp_SEG, tvb, offset, 1, TRUE);
proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, offset, 1, TRUE);
proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree_control, hf_bacapp_response_segments, tvb,
offset, 1, TRUE);
proto_tree_add_item(bacapp_tree_control, hf_bacapp_max_adpu_size, tvb,
offset, 1, TRUE);
offset++;
proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
if (bacapp_flags & 0x08) {
bacapp_seq = tvb_get_guint8(tvb, offset);
proto_tree_add_item(bacapp_tree_control, hf_bacapp_sequence_number, tvb,
offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree_control, hf_bacapp_window_size, tvb,
offset++, 1, TRUE);
}
tmp = tvb_get_guint8(tvb, offset);
proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
offset++, 1, TRUE);
tt = proto_tree_add_item(bacapp_tree, hf_bacapp_vpart, tvb,
offset, 0, TRUE);
/* Service Request follows... Variable Encoding 20.2ff */
bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
return fConfirmedServiceRequest (tvb, bacapp_tree_tag, offset, tmp);
}
static guint
fUnconfirmedRequestPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
{ /* BACnet-Unconfirmed-Request-PDU */
/* ASHRAE 135-2001 20.1.3 */
proto_item *tt, *ti;
proto_tree *bacapp_tree_tag, *bacapp_tree;
gint tmp;
tmp = tvb_get_guint8(tvb, offset+1);
ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
tmp = tvb_get_guint8(tvb, offset);
tt = proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb,
offset++, 1, TRUE);
/* Service Request follows... Variable Encoding 20.2ff */
bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
return fUnconfirmedServiceRequest (tvb, bacapp_tree_tag, offset, tmp);
}
static guint
fSimpleAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
{ /* BACnet-Simple-Ack-PDU */
/* ASHRAE 135-2001 20.1.4 */
proto_item *tc, *ti;
gint tmp;
proto_tree *bacapp_tree;
tmp = tvb_get_guint8(tvb, offset+2);
ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
offset++, 1, TRUE);
return offset;
}
static guint
fComplexAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
{ /* BACnet-Complex-Ack-PDU */
/* ASHRAE 135-2001 20.1.5 */
proto_item *tc, *tt, *ti;
proto_tree *bacapp_tree, *bacapp_tree_control, *bacapp_tree_tag;
gint tmp, bacapp_type;
tmp = (gint) tvb_get_guint8(tvb, offset);
bacapp_type = (tmp >> 4) & 0x0f;
bacapp_flags = tmp & 0x0f;
tmp = tvb_get_guint8(tvb, offset+2);
if (bacapp_flags & 0x08)
tmp = tvb_get_guint8(tvb, offset+4);
ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
proto_tree_add_item(bacapp_tree, hf_bacapp_SEG, tvb, offset, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_MOR, tvb, offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
offset++, 1, TRUE);
if (bacapp_flags & 0x08) {
bacapp_seq = tvb_get_guint8(tvb, offset);
proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
offset++, 1, TRUE);
}
tmp = tvb_get_guint8(tvb, offset);
tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
offset++, 1, TRUE);
/* Service ACK follows... */
bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
return fConfirmedServiceAck (tvb, bacapp_tree_tag, offset, tmp);
}
static guint
fSegmentAckPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
{ /* BACnet-SegmentAck-PDU */
/* ASHRAE 135-2001 20.1.6 */
proto_item *tc, *ti;
proto_tree *bacapp_tree_control, *bacapp_tree;
ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
proto_tree_add_item(bacapp_tree, hf_bacapp_NAK, tvb, offset, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
offset++, 1, TRUE);
return offset;
}
static guint
fConfirmedPrivateTransferError(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* errorType */
offset = fError (tvb,tree,offset);
break;
case 1: /* vendorID */
offset = fUnsignedTag (tvb,tree,offset,"vendor ID: ");
break;
case 2: /* serviceNumber */
offset = fUnsignedTag (tvb,tree,offset,"service Number: ");
break;
case 3: /* errorParameters */
offset = fAbstractSyntaxNType (tvb, tree, offset);
break;
default:
return offset;
}
}
return offset;
}
static guint
fCreateObjectError(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* errorType */
offset = fError (tvb,tree,offset);
break;
case 1: /* firstFailedElementNumber */
offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* errorType */
offset = fError (tvb,tree,offset);
break;
case 1: /* firstFailedElementNumber */
offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fVTSession(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
if (offset < tvb_reported_length(tvb)) { /* don't loop */
offset = fUnsignedTag (tvb,tree,offset, "local-VTSessionID: ");
offset = fUnsignedTag (tvb,tree,offset, "remote-VTSessionID: ");
offset = fAddress (tvb,tree,offset);
}
return offset;
}
static guint
fVTCloseError(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* errorType */
offset = fError (tvb,tree,offset);
break;
case 1: /* listOfVTSessionIdentifiers */
offset = fUnsignedTag (tvb,tree,offset,"VT SessionID: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fWritePropertyMultipleError(tvbuff_t *tvb, proto_tree *tree, guint offset)
{
guint lastoffset = 0;
while ((offset < tvb_reported_length(tvb))&&(offset>lastoffset)) { /* exit loop if nothing happens inside */
lastoffset = offset;
switch (fTagNo(tvb, offset)) {
case 0: /* errorType */
offset = fError (tvb,tree,offset);
break;
case 1: /* firstFailedWriteAttempt */
offset = fUnsignedTag (tvb,tree,offset,"first failed write attempt: ");
break;
default:
return offset;
}
}
return offset;
}
static guint
fError (tvbuff_t *tvb, proto_tree *tree, guint offset)
{
offset = fApplicationTypes (tvb, tree, offset, "error Class: ", BACnetErrorClass);
return fApplicationTypes (tvb, tree, offset, "error Code: ", BACnetErrorCode);
}
static guint
fBACnetError (tvbuff_t *tvb, proto_tree *tree, guint offset, guint service)
{
switch (service) {
case 8: /* no break here !!!! */
case 9:
offset = fChangeListError (tvb, tree, offset);
break;
case 10:
offset = fCreateObjectError (tvb,tree,offset);
break;
case 16:
offset = fWritePropertyMultipleError (tvb,tree,offset);
break;
case 18:
offset = fConfirmedPrivateTransferError (tvb,tree,offset);
case 22:
offset = fVTCloseError (tvb,tree,offset);
default:
return fError (tvb, tree, offset);
break;
}
return offset;
}
static guint
fErrorPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
{ /* BACnet-Error-PDU */
/* ASHRAE 135-2001 20.1.7 */
proto_item *tc, *ti, *tt;
proto_tree *bacapp_tree_control, *bacapp_tree, *bacapp_tree_tag;
guint8 tmp;
ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
offset++, 1, TRUE);
tmp = tvb_get_guint8(tvb, offset);
tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
offset++, 1, TRUE);
/* Error Handling follows... */
bacapp_tree_tag = proto_item_add_subtree(tt, ett_bacapp_tag);
return fBACnetError (tvb, bacapp_tree_tag, offset, tmp);
}
static guint
fRejectPDU(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;
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_BACnetRejectReason, tvb,
offset++, 1, TRUE);
return offset;
}
static guint
fAbortPDU(tvbuff_t *tvb, proto_tree *tree, guint offset)
{ /* BACnet-Abort-PDU */
/* ASHRAE 135-2001 20.1.9 */
proto_item *tc, *ti;
proto_tree *bacapp_tree_control, *bacapp_tree;
ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
offset++, 1, TRUE);
proto_tree_add_item(bacapp_tree, hf_BACnetAbortReason, tvb,
offset++, 1, TRUE);
return offset;
}
void
dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
gint8 tmp, bacapp_type;
tvbuff_t *next_tvb;
guint offset = 0;
guint8 bacapp_service, bacapp_reason;
if (check_col(pinfo->cinfo, COL_PROTOCOL))
col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU");
if (check_col(pinfo->cinfo, COL_INFO))
col_add_str(pinfo->cinfo, COL_INFO, "BACnet APDU ");
tmp = (gint) tvb_get_guint8(tvb, 0);
bacapp_type = (tmp >> 4) & 0x0f;
/* show some descriptive text in the INFO column */
if (check_col(pinfo->cinfo, COL_INFO))
{
col_clear(pinfo->cinfo, COL_INFO);
col_add_str(pinfo->cinfo, COL_INFO,
val_to_str(bacapp_type, BACnetTypeName, "#### unknown APDU ##### "));
switch (bacapp_type)
{
case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
/* segmented messages have 2 additional bytes */
if (tmp & BACAPP_SEGMENTED_REQUEST)
bacapp_service = tvb_get_guint8(tvb, offset + 5);
else
bacapp_service = tvb_get_guint8(tvb, offset + 3);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
BACnetConfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:
bacapp_service = tvb_get_guint8(tvb, offset + 1);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
BACnetUnconfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_SIMPLE_ACK:
bacapp_service = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
BACnetConfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_COMPLEX_ACK:
/* segmented messages have 2 additional bytes */
if (tmp & BACAPP_SEGMENTED_REQUEST)
bacapp_service = tvb_get_guint8(tvb, offset + 4);
else
bacapp_service = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
BACnetConfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_SEGMENT_ACK:
/* nothing more to add */
break;
case BACAPP_TYPE_ERROR:
bacapp_service = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_service,
BACnetConfirmedServiceChoice,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_REJECT:
bacapp_reason = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_reason,
BACnetRejectReason,
bacapp_unknown_service_str));
break;
case BACAPP_TYPE_ABORT:
bacapp_reason = tvb_get_guint8(tvb, offset + 2);
col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
val_to_str(bacapp_reason,
BACnetAbortReason,
bacapp_unknown_service_str));
break;
/* UNKNOWN */
default:
/* nothing more to add */
break;
}
}
if (tree) {
/* ASHRAE 135-2001 20.1.1 */
switch (bacapp_type) {
case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST: /* BACnet-Confirmed-Service-Request */
offset = fConfirmedRequestPDU(tvb, tree, offset);
break;
case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST: /* BACnet-Unconfirmed-Request-PDU */
offset = fUnconfirmedRequestPDU(tvb, tree, offset);
break;
case BACAPP_TYPE_SIMPLE_ACK: /* BACnet-Simple-Ack-PDU */
offset = fSimpleAckPDU(tvb, tree, offset);
break;
case BACAPP_TYPE_COMPLEX_ACK: /* BACnet-Complex-Ack-PDU */
offset = fComplexAckPDU(tvb, tree, offset);
break;
case BACAPP_TYPE_SEGMENT_ACK: /* BACnet-SegmentAck-PDU */
offset = fSegmentAckPDU(tvb, tree, offset);
break;
case BACAPP_TYPE_ERROR: /* BACnet-Error-PDU */
offset = fErrorPDU(tvb, tree, offset);
break;
case BACAPP_TYPE_REJECT: /* BACnet-Reject-PDU */
offset = fRejectPDU(tvb, tree, offset);
break;
case BACAPP_TYPE_ABORT: /* BACnet-Abort-PDU */
offset = fAbortPDU(tvb, tree, offset);
break;
}
}
next_tvb = tvb_new_subset(tvb,offset,-1,tvb_reported_length(tvb) - offset);
call_dissector(data_handle,next_tvb, pinfo, tree);
}
void
proto_register_bacapp(void)
{
static hf_register_info hf[] = {
{ &hf_bacapp_type,
{ "APDU Type", "bacapp.type",
FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, "APDU Type", HFILL }
},
{ &hf_bacapp_SEG,
{ "Segmented Request", "bacapp.segmented_request",
FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, "Segmented Request", HFILL }
},
{ &hf_bacapp_MOR,
{ "More Segments", "bacapp.more_segments",
FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL }
},
{ &hf_bacapp_SA,
{ "SA", "bacapp.SA",
FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL }
},
{ &hf_bacapp_max_adpu_size,
{ "Size of Maximum ADPU accepted", "bacapp.max_adpu_size",
FT_UINT8, BASE_DEC, VALS(BACnetMaxAPDULengthAccepted), 0x0f, "Size of Maximum ADPU accepted", HFILL }
},
{ &hf_bacapp_response_segments,
{ "Max Response Segments accepted", "bacapp.response_segments",
FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0xe0, "Max Response Segments accepted", HFILL }
},
{ &hf_bacapp_objectType,
{ "Object Type", "bacapp.objectType",
FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, "Object Type", HFILL }
},
{ &hf_bacapp_instanceNumber,
{ "Instance Number", "bacapp.instance_number",
FT_UINT32, BASE_DEC, NULL, 0x003fffff, "Instance Number", HFILL }
},
{ &hf_bacapp_invoke_id,
{ "Invoke ID", "bacapp.invoke_id",
FT_UINT8, BASE_HEX, NULL, 0, "Invoke ID", HFILL }
},
{ &hf_bacapp_sequence_number,
{ "Sequence Number", "bacapp.sequence_number",
FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL }
},
{ &hf_bacapp_window_size,
{ "Proposed Window Size", "bacapp.window_size",
FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL }
},
{ &hf_bacapp_service,
{ "Service Choice", "bacapp.confirmed_service",
FT_UINT8, BASE_DEC, VALS(BACnetConfirmedServiceChoice), 0x00, "Service Choice", HFILL }
},
{ &hf_bacapp_uservice,
{ "Unconfirmed Service Choice", "bacapp.unconfirmed_service",
FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, "Unconfirmed Service Choice", HFILL }
},
{ &hf_bacapp_NAK,
{ "NAK", "bacapp.NAK",
FT_BOOLEAN, 8, NULL, 0x02, "negativ ACK", HFILL }
},
{ &hf_bacapp_SRV,
{ "SRV", "bacapp.SRV",
FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL }
},
{ &hf_BACnetRejectReason,
{ "Reject Reason", "bacapp.reject_reason",
FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, "Reject Reason", HFILL }
},
{ &hf_BACnetAbortReason,
{ "Abort Reason", "bacapp.abort_reason",
FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 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_BACnetTagNumber,
{ "Tag Number", "bacapp.tag_number",
FT_UINT8, BASE_DEC, VALS(BACnetTagNumber), 0xF0, "Tag Number", HFILL }
},
{ &hf_BACnetTagClass,
{ "Class", "bacapp.class",
FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, "Class", HFILL }
},
{ &hf_bacapp_tag_lvt,
{ "Length Value Type", "bacapp.LVT",
FT_UINT8, BASE_DEC, NULL, 0x07, "Length Value Type", HFILL }
},
{ &hf_bacapp_tag_ProcessId,
{ "ProcessIdentifier", "bacapp.processId",
FT_UINT32, BASE_DEC, NULL, 0, "Process Identifier", HFILL }
},
{ &hf_bacapp_tag_initiatingObjectType,
{ "ObjectType", "bacapp.objectType",
FT_UINT16, BASE_DEC, VALS(BACnetObjectType), 0x00, "Object Type", HFILL }
},
};
static gint *ett[] = {
&ett_bacapp,
&ett_bacapp_control,
&ett_bacapp_tag,
&ett_bacapp_list,
&ett_bacapp_value,
};
proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU",
"BACapp", "bacapp");
proto_register_field_array(proto_bacapp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
register_dissector("bacapp", dissect_bacapp, proto_bacapp);
}
void
proto_reg_handoff_bacapp(void)
{
data_handle = find_dissector("data");
}
guint32
fConvertXXXtoUTF8 (const guint8 *in, size_t *inbytesleft, guint8 *out, size_t *outbytesleft, guint8 *fromcoding)
{ /* I don't want to let in and out be modified */
#ifdef HAVE_CONFIG_H
#if HAVE_ICONV_H
guint32 i;
iconv_t icd;
const guint8 *inp = in;
guint8 *outp = out;
const guint8 **inpp = &inp;
guint8 **outpp = &outp;
if ((icd = iconv_open ("UTF-8", fromcoding)) != (iconv_t) -1) {
i = iconv (icd, (const char**) inpp, inbytesleft, (char**) outpp, outbytesleft);
*outpp[0] = '\0';
iconv_close (icd);
return i;
}
#endif
#endif
memcpy (out, in, *inbytesleft);
out[*inbytesleft] = '\0';
*outbytesleft -= *inbytesleft;
*inbytesleft = 0;
return 0;
}