Use G_GINT64_MODIFIER, rather than the PRI[douxX]64 macros, for GLib
[metze/wireshark/wip.git] / epan / dissectors / packet-bacapp.c
1 /* packet-bacapp.c
2  * Routines for BACnet (APDU) dissection
3  * Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
4  * Enhanced by Steve Karg, 2005, <skarg@users.sourceforge.net>, Atlanta
5  * Enhanced by Herbert Lischka, 2005, <lischka@kieback-peter.de>, Berlin
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * Copied from README.developer,v 1.23
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28  */
29
30 #include "packet-bacapp.h"
31
32 /* some necessary forward function prototypes */
33 static guint
34 fApplicationTypesEnumerated (tvbuff_t *tvb, proto_tree *tree, guint offset,
35         const gchar *label, const value_string *vs);
36
37 static const char *bacapp_unknown_service_str = "unknown service";
38 static const char *ASHRAE_Reserved_Fmt = "(%d) Reserved for Use by ASHRAE";
39 static const char *Vendor_Proprietary_Fmt = "(%d) Vendor Proprietary Value";
40
41 static const value_string
42 BACnetTypeName[] = {
43         {0, "Confirmed-Request "},
44         {1, "Unconfirmed-Request "},
45         {2, "SimpleACK "},
46         {3, "ComplexACK "},
47         {4, "SegmentACK "},
48         {5, "Error "},
49         {6, "Reject "},
50         {7, "Abort "},
51         {0, NULL }
52 };
53
54 static const true_false_string segments_follow = {
55         "Segmented Request",
56         "Unsegmented Request"
57 };
58
59 static const true_false_string more_follow = {
60         "More Segments Follow",
61         "No More Segments Follow"
62 };
63
64 static const true_false_string segmented_accept = {
65         "Segmented Response accepted",
66         "Segmented Response not accepted"
67 };
68
69 static const true_false_string
70 BACnetTagClass = {
71         "Context Specific Tag",
72         "Application Tag"
73 };
74
75 static const value_string
76 BACnetMaxSegmentsAccepted [] = {
77         {0,"Unspecified"},
78         {1,"2 segments"},
79         {2,"4 segments"},
80         {3,"8 segments"},
81         {4,"16 segments"},
82         {5,"32 segments"},
83         {6,"64 segments"},
84         {7,"Greater than 64 segments"},
85         {0,NULL }
86 };
87
88 static const value_string
89 BACnetMaxAPDULengthAccepted [] = {
90         {0,"Up to MinimumMessageSize (50 octets)"},
91         {1,"Up to 128 octets"},
92         {2,"Up to 206 octets (fits in a LonTalk frame)"},
93         {3,"Up to 480 octets (fits in an ARCNET frame)"},
94         {4,"Up to 1024 octets"},
95         {5,"Up to 1476 octets (fits in an ISO 8802-3 frame)"},
96         {6,"reserved by ASHRAE"},
97         {7,"reserved by ASHRAE"},
98         {8,"reserved by ASHRAE"},
99         {9,"reserved by ASHRAE"},
100         {10,"reserved by ASHRAE"},
101         {11,"reserved by ASHRAE"},
102         {12,"reserved by ASHRAE"},
103         {13,"reserved by ASHRAE"},
104         {14,"reserved by ASHRAE"},
105         {15,"reserved by ASHRAE"},
106         {0,NULL}
107 };
108
109 static const value_string
110 BACnetRejectReason [] = {
111         {0,"other"},
112         {1,"buffer-overflow"},
113         {2,"inconsistent-parameters"},
114         {3,"invalid-parameter-data-type"},
115         {4,"invalid-tag"},
116         {5,"missing-required-parameter"},
117         {6,"parameter-out-of-range"},
118         {7,"too-many-arguments"},
119         {8,"undefined-enumeration"},
120         {9,"unrecognized-service"},
121         {0,NULL}
122 };
123
124 static const value_string
125 BACnetApplicationTagNumber [] = {
126         {0,"Null"},
127         {1,"Boolean"},
128         {2,"Unsigned Integer"},
129         {3,"Signed Integer (2's complement notation)"},
130         {4,"Real (ANSI/IEE-754 floating point)"},
131         {5,"Double (ANSI/IEE-754 double precision floating point)"},
132         {6,"Octet String"},
133         {7,"Character String"},
134         {8,"Bit String"},
135         {9,"Enumerated"},
136         {10,"Date"},
137         {11,"Time"},
138         {12,"BACnetObjectIdentifier"},
139         {13,"reserved by ASHRAE"},
140         {14,"reserved by ASHRAE"},
141         {15,"reserved by ASHRAE"},
142         {0,NULL}
143 };
144
145 static const value_string
146 BACnetAction [] = {
147         {0,"direct"},
148         {1,"reverse"},
149         {0,NULL}
150 };
151
152 static const value_string
153 BACnetFileAccessMethod [] = {
154         {0,"record-access"},
155         {1,"stream-access"},
156         {0,NULL}
157 };
158
159 /* For some reason, BACnet defines the choice parameter
160    in the file read and write services backwards from the
161    BACnetFileAccessMethod enumeration.
162 */
163 static const value_string
164 BACnetFileAccessOption [] = {
165         {0,"stream access"},
166         {1,"record access"},
167         {0,NULL}
168 };
169
170 static const value_string
171 BACnetFileStartOption [] = {
172         {0, "File Start Position: "},
173         {1, "File Start Record: "},
174         {0, NULL}
175 };
176
177 static const value_string
178 BACnetFileRequestCount [] = {
179         {0, "Requested Octet Count: "},
180         {1, "Requested Record Count: "},
181         {0, NULL}
182 };
183
184 static const value_string
185 BACnetFileWriteInfo [] = {
186         {0, "File Data: "},
187         {1, "Record Count: "},
188         {0, NULL}
189 };
190
191 static const value_string
192 BACnetAbortReason [] = {
193         {0,"other"},
194         {1,"buffer-overflow"},
195         {2,"invalid-apdu-in-this-state"},
196         {3,"preempted-by-higher-priority-task"},
197         {4,"segmentation-not-supported"},
198         {0,NULL}
199 };
200
201 static const value_string
202 BACnetLifeSafetyMode [] = {
203         {0,"off"},
204         {1,"on"},
205         {2,"test"},
206         {3,"manned"},
207         {4,"unmanned"},
208         {5,"armed"},
209         {6,"disarmed"},
210         {7,"prearmed"},
211         {8,"slow"},
212         {9,"fast"},
213         {10,"disconnected"},
214         {11,"enabled"},
215         {12,"disabled"},
216         {13,"atomic-release-disabled"},
217         {14,"default"},
218         {0,NULL}
219 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
220    Enumerated values 256-65535 may be used by others subject to
221    procedures and constraints described in Clause 23. */
222 };
223
224 static const value_string
225 BACnetLifeSafetyOperation [] = {
226         {0,"none"},
227         {1,"silence"},
228         {2,"silence-audible"},
229         {3,"silence-visual"},
230         {4,"reset"},
231         {5,"reset-alarm"},
232         {6,"reset-fault"},
233         {7,"unsilence"},
234         {8,"unsilence-audible"},
235         {9,"unsilence-visual"},
236         {0,NULL}
237 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
238    Enumerated values 64-65535 may be used by others subject to
239    procedures and constraints described in Clause 23. */
240 };
241
242 static const value_string
243 BACnetLimitEnable [] = {
244         {0,"lowLimitEnable"},
245         {1,"highLimitEnable"},
246         {0,NULL}
247 };
248
249 static const value_string
250 BACnetLifeSafetyState [] = {
251         {0,"quiet"},
252         {1,"pre-alarm"},
253         {2,"alarm"},
254         {3,"fault"},
255         {4,"fault-pre-alarm"},
256         {5,"fault-alarm"},
257         {6,"not-ready"},
258         {7,"active"},
259         {8,"tamper"},
260         {9,"test-alarm"},
261         {10,"test-active"},
262         {11,"test-fault"},
263         {12,"test-fault-alarm"},
264         {13,"holdup"},
265         {14,"duress"},
266         {15,"tamper-alarm"},
267         {16,"abnormal"},
268         {17,"emergency-power"},
269         {18,"delayed"},
270         {19,"blocked"},
271         {20,"local-alarm"},
272         {21,"general-alarm"},
273         {22,"supervisory"},
274         {23,"test-supervisory"},
275         {0,NULL}
276 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
277    Enumerated values 256-65535 may be used by others subject to
278    procedures and constraints described in Clause 23. */
279 };
280
281 static const value_string
282 BACnetConfirmedServiceChoice [] = {
283         {0,"acknowledgeAlarm"},
284         {1,"confirmedCOVNotification"},
285         {2,"confirmedEventNotification"},
286         {3,"getAlarmSummary"},
287         {4,"getEnrollmentSummary"},
288         {5,"subscribeCOV"},
289         {6,"atomicReadFile"},
290         {7,"atomicWriteFile"},
291         {8,"addListElement"},
292         {9,"removeListElement"},
293         {10,"createObject"},
294         {11,"deleteObject"},
295         {12,"readProperty"},
296         {13,"readPropertyConditional"},
297         {14,"readPropertyMultiple"},
298         {15,"writeProperty"},
299         {16,"writePropertyMultiple"},
300         {17,"deviceCommunicationControl"},
301         {18,"confirmedPrivateTransfer"},
302         {19,"confirmedTextMessage"},
303         {20,"reinitializeDevice"},
304         {21,"vtOpen"},
305         {22,"vtClose"},
306         {23,"vtData"},
307         {24,"authenticate"},
308         {25,"requestKey"},
309         {26,"readRange"},
310         {27,"lifeSafetyOperation"},
311         {28,"subscribeCOVProperty"},
312         {29,"getEventInformation"},
313         {30,"reserved by ASHRAE"},
314         {0, NULL}
315 };
316
317 static const value_string
318 BACnetReliability [] = {
319         {0,"no-fault-detected"},
320         {1,"no-sensor"},
321         {2,"over-range"},
322         {3,"under-range"},
323         {4,"open-loop"},
324         {5,"shorted-loop"},
325         {6,"no-output"},
326         {7,"unreliable-other"},
327         {8,"process-error"},
328         {9,"multi-state-fault"},
329         {0,NULL}
330 };
331
332 static const value_string
333 BACnetUnconfirmedServiceChoice [] = {
334         {0,"i-Am"},
335         {1,"i-Have"},
336         {2,"unconfirmedCOVNotification"},
337         {3,"unconfirmedEventNotification"},
338         {4,"unconfirmedPrivateTransfer"},
339         {5,"unconfirmedTextMessage"},
340         {6,"timeSynchronization"},
341         {7,"who-Has"},
342         {8,"who-Is"},
343         {9,"utcTimeSynchonization"},
344         {0,NULL}
345 };
346
347 static const value_string
348 BACnetUnconfirmedServiceRequest [] = {
349         {0,"i-Am-Request"},
350         {1,"i-Have-Request"},
351         {2,"unconfirmedCOVNotification-Request"},
352         {3,"unconfirmedEventNotification-Request"},
353         {4,"unconfirmedPrivateTransfer-Request"},
354         {5,"unconfirmedTextMessage-Request"},
355         {6,"timeSynchronization-Request"},
356         {7,"who-Has-Request"},
357         {8,"who-Is-Request"},
358         {9,"utcTimeSynchonization-Request"},
359         {0,NULL}
360 };
361
362 static const value_string
363 BACnetObjectType [] = {
364         {0,"analog-input object"},
365         {1,"analog-output object"},
366         {2,"analog-value object"},
367         {3,"binary-input object"},
368         {4,"binary-output object"},
369         {5,"binary-value object"},
370         {6,"calendar object"},
371         {7,"command object"},
372         {8,"device object"},
373         {9,"event-enrollment object"},
374         {10,"file object"},
375         {11,"group object"},
376         {12,"loop object"},
377         {13,"multi-state-input object"},
378         {14,"multi-state-output object"},
379         {15,"notification-class object"},
380         {16,"program object"},
381         {17,"schedule object"},
382         {18,"averaging object"},
383         {19,"multi-state-value object"},
384         {20,"trend-log object"},
385         {21,"life-safety-point object"},
386         {22,"life-safety-zone object"},
387         {23,"accumulator object"},
388         {24,"pulse-converter object"},
389         {25,"event-log object"},
390         {26,"global-group object"},
391         {27,"trend-log-multiple object"},
392         {28,"load-control object"},
393         {29,"structured-view object"},
394         {0, NULL}
395 /* Enumerated values 0-127 are reserved for definition by ASHRAE.
396    Enumerated values 128-1023 may be used by others subject to
397    the procedures and constraints described in Clause 23. */
398 };
399
400 static const value_string
401 BACnetEngineeringUnits [] = {
402         {0,"Sq Meters"},
403         {1,"Sq Feet"},
404         {2,"Milliamperes"},
405         {3,"Amperes"},
406         {4,"Ohms"},
407         {5,"Volts"},
408         {6,"Kilovolts"},
409         {7,"Megavolts"},
410         {8,"Volt Amperes"},
411         {9,"Kilovolt Amperes"},
412         {10,"Megavolt Amperes"},
413         {11,"Volt Amperes Reactive"},
414         {12,"Kilovolt Amperes Reactive"},
415         {13,"Megavolt Amperes Ractive"},
416         {14,"Degrees Phase"},
417         {15,"Power Factor"},
418         {16,"Joules"},
419         {17,"Kilojoules"},
420         {18,"Watt Hours"},
421         {19,"Kilowatt Hours"},
422         {20,"BTUs"},
423         {21,"Therms"},
424         {22,"Ton Hours"},
425         {23,"Joules Per Kg Dry Air"},
426         {24,"BTUs Per Pound Dry Air"},
427         {25,"Cycles Per Hour"},
428         {26,"Cycles Per Minute"},
429         {27,"Hertz"},
430         {28,"Gramms Of Water Per Kilogram Dry Air"},
431         {29,"Relative Humidity"},
432         {30,"Millimeters"},
433         {31,"Meters"},
434         {32,"Inches"},
435         {33,"Feed"},
436         {34,"Watts Per Sq Foot"},
437         {35,"Watts Per Sq meter"},
438         {36,"Lumens"},
439         {37,"Lux"},
440         {38,"Foot Candels"},
441         {39,"Kilograms"},
442         {40,"Pounds Mass"},
443         {41,"Tons"},
444         {42,"Kgs per Second"},
445         {43,"Kgs Per Minute"},
446         {44,"Kgs Per Hour"},
447         {45,"Pounds Mass Per Minute"},
448         {46,"Pounds Mass Per Hour"},
449         {47,"Watt"},
450         {48,"Kilowatts"},
451         {49,"Megawatts"},
452         {50,"BTUs Per Hour"},
453         {51,"Horsepower"},
454         {52,"Tons Refrigeration"},
455         {53,"Pascals"},
456         {54,"Kilopascals"},
457         {55,"Bars"},
458         {56,"Pounds Force Per Square Inch"},
459         {57,"Centimeters Of Water"},
460         {58,"Inches Of Water"},
461         {59,"Millimeters Of Mercury"},
462         {60,"Centimeters Of Mercury"},
463         {61,"Inches Of Mercury"},
464         {62,"Degrees Celsius"},
465         {63,"Degress Kelvin"},
466         {64,"Degrees Fahrenheit"},
467         {65,"Degree Days Celsius"},
468         {66,"Degree Days Fahrenheit"},
469         {67,"Years"},
470         {68,"Months"},
471         {69,"Weeks"},
472         {70,"Days"},
473         {71,"Hours"},
474         {72,"Minutes"},
475         {73,"Seconds"},
476         {74,"Meters Per Second"},
477         {75,"Kilometers Per Hour"},
478         {76,"Feed Per Second"},
479         {77,"Feet Per Minute"},
480         {78,"Miles Per Hour"},
481         {79,"Cubic Feet"},
482         {80,"Cubic Meters"},
483         {81,"Imperial Gallons"},
484         {82,"Liters"},
485         {83,"US Gallons"},
486         {84,"Cubic Feet Per Minute"},
487         {85,"Cubic Meters Per Second"},
488         {86,"Imperial Gallons Per Minute"},
489         {87,"Liters Per Second"},
490         {88,"Liters Per Minute"},
491         {89,"US Gallons Per Minute"},
492         {90,"Degrees Angular"},
493         {91,"Degrees Celsius Per Hour"},
494         {92,"Degrees Celsius Per Minute"},
495         {93,"Degrees Fahrenheit Per Hour"},
496         {94,"Degrees Fahrenheit Per Minute"},
497         {95,"No Units"},
498         {96,"Parts Per Million"},
499         {97,"Parts Per Billion"},
500         {98,"Percent"},
501         {99,"Pecent Per Second"},
502         {100,"Per Minute"},
503         {101,"Per Second"},
504         {102,"Psi Per Degree Fahrenheit"},
505         {103,"Radians"},
506         {104,"Revolutions Per Min"},
507         {105,"Currency1"},
508         {106,"Currency2"},
509         {107,"Currency3"},
510         {108,"Currency4"},
511         {109,"Currency5"},
512         {110,"Currency6"},
513         {111,"Currency7"},
514         {112,"Currency8"},
515         {113,"Currency9"},
516         {114,"Currency10"},
517         {115,"Sq Inches"},
518         {116,"Sq Centimeters"},
519         {117,"BTUs Per Pound"},
520         {118,"Centimeters"},
521         {119,"Pounds Mass Per Second"},
522         {120,"Delta Degrees Fahrenheit"},
523         {121,"Delta Degrees Kelvin"},
524         {122,"Kilohms"},
525         {123,"Megohms"},
526         {124,"Millivolts"},
527         {125,"Kilojoules Per Kg"},
528         {126,"Megajoules"},
529         {127,"Joules Per Degree Kelvin"},
530         {128,"Joules Per Kg Degree Kelvin"},
531         {129,"Kilohertz"},
532         {130,"Megahertz"},
533         {131,"Per Hour"},
534         {132,"Milliwatts"},
535         {133,"Hectopascals"},
536         {134,"Millibars"},
537         {135,"Cubic Meters Per Hour"},
538         {136,"Liters Per Hour"},
539         {137,"KWatt Hours Per Square Meter"},
540         {138,"KWatt Hours Per Square Foot"},
541         {139,"Megajoules Per Square Meter"},
542         {140,"Megajoules Per Square Foot"},
543         {141,"Watts Per Sq Meter Degree Kelvin"},
544         {142,"Cubic Feet Per Second"},
545         {143,"Percent Obstruction Per Foot"},
546         {144,"Percent Obstruction Per Meter"},
547         {145,"milliohms"},
548         {146,"megawatt-hours"},
549         {147,"kilo-btus"},
550         {148,"mega-btus"},
551         {149,"kilojoules-per-kilogram-dry-air"},
552         {150,"megajoules-per-kilogram-dry-air"},
553         {151,"kilojoules-per-degree-Kelvin"},
554         {152,"megajoules-per-degree-Kelvin"},
555         {153,"newton"},
556         {154,"grams-per-second"},
557         {155,"grams-per-minute"},
558         {156,"tons-per-hour"},
559         {157,"kilo-btus-per-hour"},
560         {158,"hundredths-seconds"},
561         {159,"milliseconds"},
562         {160,"newton-meters"},
563         {161,"millimeters-per-second"},
564         {162,"millimeters-per-minute"},
565         {163,"meters-per-minute"},
566         {164,"meters-per-hour"},
567         {165,"cubic-meters-per-minute"},
568         {166,"meters-per-second-per-second"},
569         {167,"amperes-per-meter"},
570         {168,"amperes-per-square-meter"},
571         {169,"ampere-square-meters"},
572         {170,"farads"},
573         {171,"henrys"},
574         {172,"ohm-meters"},
575         {173,"siemens"},
576         {174,"siemens-per-meter"},
577         {175,"teslas"},
578         {176,"volts-per-degree-Kelvin"},
579         {177,"volts-per-meter"},
580         {178,"webers"},
581         {179,"candelas"},
582         {180,"candelas-per-square-meter"},
583         {181,"degrees-Kelvin-per-hour"},
584         {182,"degrees-Kelvin-per-minute"},
585         {183,"joule-seconds"},
586         {184,"radians-per-second"},
587         {185,"square-meters-per-Newton"},
588         {186,"kilograms-per-cubic-meter"},
589         {187,"newton-seconds"},
590         {188,"newtons-per-meter"},
591         {189,"watts-per-meter-per-degree-Kelvin"},
592         {0,NULL}
593 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
594    Enumerated values 256-65535 may be used by others subject to
595    the procedures and constraints described in Clause 23. */
596 };
597
598 static const value_string
599 BACnetErrorCode [] = {
600         {0,"other"},
601         {1,"authentication-failed"},
602         {2,"character-set-not-supported"},
603         {3,"configuration-in-progress"},
604         {4,"device-busy"},
605         {5,"file-access-denied"},
606         {6,"incompatible-security-levels"},
607         {7,"inconsistent-parameters"},
608         {8,"inconsistent-selection-criterion"},
609         {9,"invalid-data-type"},
610         {10,"invalid-file-access-method"},
611         {11,"invalid-file-start-position"},
612         {12,"invalid-operator-name"},
613         {13,"invalid-parameter-data-type"},
614         {14,"invalid-time-stamp"},
615         {15,"key-generation-error"},
616         {16,"missing-required-parameter"},
617         {17,"no-objects-of-specified-type"},
618         {18,"no-space-for-object"},
619         {19,"no-space-to-add-list-element"},
620         {20,"no-space-to-write-property"},
621         {21,"no-vt-sessions-available"},
622         {22,"property-is-not-a-list"},
623         {23,"object-deletion-not-permitted"},
624         {24,"object-identifier-already-exists"},
625         {25,"operational-problem"},
626         {26,"password-failure"},
627         {27,"read-access-denied"},
628         {28,"security-not-supported"},
629         {29,"service-request-denied"},
630         {30,"timeout"},
631         {31,"unknown-object"},
632         {32,"unknown-property"},
633         {33,"removed enumeration"},
634         {34,"unknown-vt-class"},
635         {35,"unknown-vt-session"},
636         {36,"unsupported-object-type"},
637         {37,"value-out-of-range"},
638         {38,"vt-session-already-closed"},
639         {39,"vt-session-termination-failure"},
640         {40,"write-access-denied"},
641         {41,"character-set-not-supported"},
642         {42,"invalid-array-index"},
643         {43,"cov-subscription-failed"},
644         {44,"not-cov-property"},
645         {45,"optional-functionaltity-not-supported"},
646         {46,"invalid-configuration-data"},
647         {47,"datatype-not-supported"},
648         {48,"duplicate-name"},
649         {49,"duplicate-object-id"},
650         {50,"property-is-not-an-array"},
651         {0, NULL}
652 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
653    Enumerated values 256-65535 may be used by others subject to the
654    procedures and constraints described in Clause 23. */
655 };
656
657 static const value_string
658 BACnetPropertyIdentifier [] = {
659         {0,"acked-transition"},
660         {1,"ack-required"},
661         {2,"action"},
662         {3,"action-text"},
663         {4,"active-text"},
664         {5,"active-vt-session"},
665         {6,"alarm-value"},
666         {7,"alarm-values"},
667         {8,"all"},
668         {9,"all-write-successful"},
669         {10,"apdu-segment-timeout"},
670         {11,"apdu-timeout"},
671         {12,"application-software-version"},
672         {13,"archive"},
673         {14,"bias"},
674         {15,"change-of-state-count"},
675         {16,"change-of-state-time"},
676         {17,"notification-class"},
677         {18,"the property in this place was deleted"},
678         {19,"controlled-variable-reference"},
679         {20,"controlled-variable-units"},
680         {21,"controlled-variable-value"},
681         {22,"cov-increment"},
682         {23,"datelist"},
683         {24,"daylights-savings-status"},
684         {25,"deadband"},
685         {26,"derivative-constant"},
686         {27,"derivative-constant-units"},
687         {28,"description"},
688         {29,"description-of-halt"},
689         {30,"device-address-binding"},
690         {31,"device-type"},
691         {32,"effective-period"},
692         {33,"elapsed-active-time"},
693         {34,"error-limit"},
694         {35,"event-enable"},
695         {36,"event-state"},
696         {37,"event-type"},
697         {38,"exception-schedule"},
698         {39,"fault-values"},
699         {40,"feedback-value"},
700         {41,"file-access-method"},
701         {42,"file-size"},
702         {43,"file-type"},
703         {44,"firmware-revision"},
704         {45,"high-limit"},
705         {46,"inactive-text"},
706         {47,"in-progress"},
707         {48,"instance-of"},
708         {49,"integral-constant"},
709         {50,"integral-constant-units"},
710         {51,"issue-confirmed-notifications"},
711         {52,"limit-enable"},
712         {53,"list-of-group-members"},
713         {54,"list-of-object-property-references"},
714         {55,"list-of-session-keys"},
715         {56,"local-date"},
716         {57,"local-time"},
717         {58,"location"},
718         {59,"low-limit"},
719         {60,"manipulated-variable-reference"},
720         {61,"maximum-output"},
721         {62,"max-apdu-length-accepted"},
722         {63,"max-info-frames"},
723         {64,"max-master"},
724         {65,"max-pres-value"},
725         {66,"minimum-off-time"},
726         {67,"minimum-on-time"},
727         {68,"minimum-output"},
728         {69,"min-pres-value"},
729         {70,"model-name"},
730         {71,"modification-date"},
731         {72,"notify-type"},
732         {73,"number-of-APDU-retries"},
733         {74,"number-of-states"},
734         {75,"object-identifier"},
735         {76,"object-list"},
736         {77,"object-name"},
737         {78,"object-property-reference"},
738         {79,"object-type"},
739         {80,"optional"},
740         {81,"out-of-service"},
741         {82,"output-units"},
742         {83,"event-parameters"},
743         {84,"polarity"},
744         {85,"present-value"},
745         {86,"priority"},
746         {87,"priority-array"},
747         {88,"priority-for-writing"},
748         {89,"process-identifier"},
749         {90,"program-change"},
750         {91,"program-location"},
751         {92,"program-state"},
752         {93,"proportional-constant"},
753         {94,"proportional-constant-units"},
754         {95,"protocol-conformance-class"},
755         {96,"protocol-object-types-supported"},
756         {97,"protocol-services-supported"},
757         {98,"protocol-version"},
758         {99,"read-only"},
759         {100,"reason-for-halt"},
760         {101,"recipient"},
761         {102,"recipient-list"},
762         {103,"reliability"},
763         {104,"relinquish-default"},
764         {105,"required"},
765         {106,"resolution"},
766         {107,"segmentation-supported"},
767         {108,"setpoint"},
768         {109,"setpoint-reference"},
769         {110,"state-text"},
770         {111,"status-flags"},
771         {112,"system-status"},
772         {113,"time-delay"},
773         {114,"time-of-active-time-reset"},
774         {115,"time-of-state-count-reset"},
775         {116,"time-synchronization-recipients"},
776         {117,"units"},
777         {118,"update-interval"},
778         {119,"utc-offset"},
779         {120,"vendor-identifier"},
780         {121,"vendor-name"},
781         {122,"vt-class-supported"},
782         {123,"weekly-schedule"},
783         {124,"attempted-samples"},
784         {125,"average-value"},
785         {126,"buffer-size"},
786         {127,"client-cov-increment"},
787         {128,"cov-resubscription-interval"},
788         {129,"current-notify-time"},
789         {130,"event-time-stamp"},
790         {131,"log-buffer"},
791         {132,"log-device-object-property"},
792         {133,"enable"}, /* per ANSI/ASHRAE 135-2004 addendum B */
793         {134,"log-interval"},
794         {135,"maximum-value"},
795         {136,"minimum-value"},
796         {137,"notification-threshold"},
797         {138,"previous-notify-time"},
798         {139,"protocol-revision"},
799         {140,"records-since-notification"},
800         {141,"record-count"},
801         {142,"start-time"},
802         {143,"stop-time"},
803         {144,"stop-when-full"},
804         {145,"total-record-count"},
805         {146,"valid-samples"},
806         {147,"window-interval"},
807         {148,"window-samples"},
808         {149,"maximum-value-time-stamp"},
809         {150,"minimum-value-time-stamp"},
810         {151,"variance-value"},
811         {152,"active-cov-subscriptions"},
812         {153,"backup-failure-timeout"},
813         {154,"configuration-files"},
814         {155,"database-revision"},
815         {156,"direct-reading"},
816         {157,"last-restore-time"},
817         {158,"maintenance-required"},
818         {159,"member-of"},
819         {160,"mode"},
820         {161,"operation-expected"},
821         {162,"setting"},
822         {163,"silenced"},
823         {164,"tracking-value"},
824         {165,"zone-members"},
825         {166,"life-safety-alarm-values"},
826         {167,"max-segments-accepted"},
827         {168,"profile-name"},
828         {169,"auto-slave-discovery"},
829         {170,"manual-slave-address-binding"},
830         {171,"slave-address-binding"},
831         {172,"slave-proxy-enable"},
832         {173,"last-notify-time"},
833         {174,"schedule-default"},
834         {175,"accepted-modes"},
835         {176,"adjust-value"},
836         {177,"count"},
837         {178,"count-before-change"},
838         {179,"count-change-time"},
839         {180,"cov-period"},
840         {181,"input-reference"},
841         {182,"limit-monitoring-interval"},
842         {183,"logging-device"},
843         {184,"logging-record"},
844         {185,"prescale"},
845         {186,"pulse-rate"},
846         {187,"scale"},
847         {188,"scale-factor"},
848         {189,"update-time"},
849         {190,"value-before-change"},
850         {191,"value-set"},
851         {192,"value-change-time"},
852         {193,"align-intervals"},
853         {194,"group-member-names"},
854         {195,"interval-offset"},
855         {196,"last-restart-reason"},
856         {197,"logging-type"},
857         {198,"member-status-flags"},
858         {199,"notification-period"},
859         {200,"previous-notify-record"},
860         {201,"requested-update-interval"},
861         {202,"restart-notification-recipients"},
862         {203,"time-of-device-restart"},
863         {204,"time-synchronization-recipients"},
864         {205,"trigger"},
865         {206,"UTC-time-synchronization-recipients"},
866         /* enumerations 207-211 are used in Addendum d to 
867            ANSI/ASHRAE 135-2004 */
868         {207,"node-subtype"},
869         {208,"node-type"},
870         {209,"structured-object-list"},
871         {210,"subordinate-annotations"},
872         {211,"subordinate-list"},
873         {0, NULL}
874 /* Enumerated values 0-511 are reserved for definition by ASHRAE.
875    Enumerated values 512-4194303 may be used by others subject to
876    the procedures and constraints described in Clause 23. */
877 };
878
879 static const value_string
880 BACnetBinaryPV [] = {
881         {0,"inactive"},
882         {1,"active"},
883         {0,NULL}
884 };
885
886
887 static const value_string
888 BACnetCharacterSet [] = {
889         {0,"ANSI X3.4"},
890         {1,"IBM/Microsoft DBCS"},
891         {2,"JIS C 6226"},
892         {3,"ISO 10646(UCS-4)"},
893         {4,"ISO 10646(UCS-2)"},
894         {5,"ISO 18859-1"},
895         {0,NULL}
896 };
897
898 static const value_string
899 BACnetStatusFlags [] = {
900         {0,"in-alarm"},
901         {1,"fault"},
902         {2,"overridden"},
903         {3,"out-of-service"},
904         {0,NULL}
905 };
906
907 static const value_string
908 BACnetMessagePriority [] = {
909         {0,"normal"},
910         {1,"urgent"},
911         {0,NULL}
912 };
913
914 static const value_string
915 BACnetAcknowledgementFilter [] = {
916         {0,"all"},
917         {1,"acked"},
918         {2,"not-acked"},
919         {0,NULL}
920 };
921
922 static const value_string
923 BACnetResultFlags [] = {
924         {0,"firstitem"},
925         {1,"lastitem"},
926         {2,"moreitems"},
927         {0,NULL}
928 };
929
930 static const value_string
931 BACnetRelationSpecifier [] = {
932         {0,"equal"},
933         {1,"not-equal"},
934         {2,"less-than"},
935         {3,"greater-than"},
936         {4,"less-than-or-equal"},
937         {5,"greater-than-or-equal"},
938         {0,NULL}
939 };
940
941 static const value_string
942 BACnetSelectionLogic [] = {
943         {0,"and"},
944         {1,"or"},
945         {2,"all"},
946         {0,NULL}
947 };
948
949 static const value_string
950 BACnetEventStateFilter [] = {
951         {0,"offnormal"},
952         {1,"fault"},
953         {2,"normal"},
954         {3,"all"},
955         {4,"active"},
956         {0,NULL}
957 };
958
959 static const value_string
960 BACnetEventTransitionBits [] = {
961         {0,"to-offnormal"},
962         {1,"to-fault"},
963         {2,"to-normal"},
964         {0,NULL}
965 };
966
967 static const value_string
968 BACnetSegmentation [] = {
969         {0,"segmented-both"},
970         {1,"segmented-transmit"},
971         {2,"segmented-receive"},
972         {3,"no-segmentation"},
973         {0,NULL}
974 };
975
976 static const value_string
977 BACnetSilencedState [] = {
978         {0,"unsilenced"},
979         {1,"audible-silenced"},
980         {2,"visible-silenced"},
981         {3,"all-silenced"},
982         {0,NULL}
983 };
984
985 static const value_string
986 BACnetDeviceStatus [] = {
987         {0,"operational"},
988         {1,"operational-read-only"},
989         {2,"download-required"},
990         {3,"download-in-progress"},
991         {4,"non-operational"},
992         {5,"backup-in-progress"},
993         {0,NULL}
994 };
995
996 static const value_string
997 BACnetEnableDisable [] = {
998         {0,"enable"},
999         {1,"disable"},
1000         {2,"disable-initiation"},
1001         {0,NULL}
1002 };
1003
1004 static const value_string
1005 months [] = {
1006         {1,"January" },
1007         {2,"February" },
1008         {3,"March" },
1009         {4,"April" },
1010         {5,"May" },
1011         {6,"June" },
1012         {7,"July" },
1013         {8,"August" },
1014         {9,"September" },
1015         {10,"October" },
1016         {11,"November" },
1017         {12,"December" },
1018         {255,"any month" },
1019         {0,NULL }
1020 };
1021
1022 static const value_string
1023 weekofmonth [] = {
1024         {1,"days numbered 1-7" },
1025         {2,"days numbered 8-14" },
1026         {3,"days numbered 15-21" },
1027         {4,"days numbered 22-28" },
1028         {5,"days numbered 29-31" },
1029         {6,"last 7 days of this month" },
1030         {255,"any week of this month" },
1031         {0,NULL }
1032 };
1033
1034 static const value_string
1035 days [] = {
1036         {1,"Monday" },
1037         {2,"Tuesday" },
1038         {3,"Wednesday" },
1039         {4,"Thursday" },
1040         {5,"Friday" },
1041         {6,"Saturday" },
1042         {7,"Sunday" },
1043         {255,"any day of week" },
1044         {0,NULL }
1045 };
1046
1047 static const value_string
1048 BACnetErrorClass [] = {
1049         {0,"device" },
1050         {1,"object" },
1051         {2,"property" },
1052         {3,"resources" },
1053         {4,"security" },
1054         {5,"services" },
1055         {6,"vt" },
1056         {0,NULL }
1057 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
1058    Enumerated values64-65535 may be used by others subject to
1059    the procedures and constraints described in Clause 23. */
1060 };
1061
1062 static const value_string
1063 BACnetVTClass [] = {
1064         {0,"default-terminal" },
1065         {1,"ansi-x3-64" },
1066         {2,"dec-vt52" },
1067         {3,"dec-vt100" },
1068         {4,"dec-vt200" },
1069         {5,"hp-700-94" },
1070         {6,"ibm-3130" },
1071         {0,NULL }
1072 };
1073
1074 static const value_string
1075 BACnetEventType [] = {
1076         {0,"change-of-bitstring" },
1077         {1,"change-of-state" },
1078         {2,"change-of-value" },
1079         {3,"command-failure" },
1080         {4,"floating-limit" },
1081         {5,"out-of-range" },
1082         {6,"complex-event-type" },
1083         {7,"buffer-ready" },
1084         {8,"change-of-life-safety" },
1085         {9,"extended" },
1086         {10,"buffer-ready" },
1087         {11,"unsigned-range" },
1088         {0,NULL }
1089 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
1090    Enumerated values 64-65535 may be used by others subject to
1091    the procedures and constraints described in Clause 23.
1092    It is expected that these enumerated values will correspond
1093    to the use of the complex-event-type CHOICE [6] of the
1094    BACnetNotificationParameters production. */
1095 };
1096
1097 static const value_string
1098 BACnetEventState [] = {
1099         {0,"normal" },
1100         {1,"fault" },
1101         {2,"offnormal" },
1102         {3,"high-limit" },
1103         {4,"low-limit" },
1104         {5,"life-safety-alarm" },
1105         {0,NULL }
1106 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
1107    Enumerated values 64-65535 may be used by others subject to
1108    the procedures and constraints described in Clause 23.  */
1109 };
1110
1111 static const value_string
1112 BACnetLogStatus [] = {
1113         {0,"log-disabled" },
1114         {1,"buffer-purged" },
1115         {0,NULL }
1116 };
1117
1118 static const value_string
1119 BACnetMaintenance [] = {
1120         {0,"none" },
1121         {1,"periodic-test" },
1122         {2,"need-service-operational" },
1123         {3,"need-service-inoperative" },
1124         {0,NULL }
1125 };
1126
1127 static const value_string
1128 BACnetNotifyType [] = {
1129         {0,"alarm" },
1130         {1,"event" },
1131         {2,"ack-notification" },
1132         {0,NULL }
1133 };
1134
1135 static const value_string
1136 BACnetServicesSupported [] = {
1137         {0,"acknowledgeAlarm"},
1138         {1,"confirmedCOVNotification"},
1139         {2,"confirmedEventNotification"},
1140         {3,"getAlarmSummary"},
1141         {4,"getEnrollmentSummary"},
1142         {5,"subscribeCOV"},
1143         {6,"atomicReadFile"},
1144         {7,"atomicWriteFile"},
1145         {8,"addListElement"},
1146         {9,"removeListElement"},
1147         {10,"createObject"},
1148         {11,"deleteObject"},
1149         {12,"readProperty"},
1150         {13,"readPropertyConditional"},
1151         {14,"readPropertyMultiple"},
1152         {15,"writeProperty"},
1153         {16,"writePropertyMultiple"},
1154         {17,"deviceCommunicationControl"},
1155         {18,"confirmedPrivateTransfer"},
1156         {19,"confirmedTextMessage"},
1157         {20,"reinitializeDevice"},
1158         {21,"vtOpen"},
1159         {22,"vtClose"},
1160         {23,"vtData"},
1161         {24,"authenticate"},
1162         {25,"requestKey"},
1163         {26,"i-Am"},
1164         {27,"i-Have"},
1165         {28,"unconfirmedCOVNotification"},
1166         {29,"unconfirmedEventNotification"},
1167         {30,"unconfirmedPrivateTransfer"},
1168         {31,"unconfirmedTextMessage"},
1169         {32,"timeSynchronization"},
1170         {33,"who-Has"},
1171         {34,"who-Is"},
1172         {35,"readRange"},
1173         {36,"utcTimeSynchronization"},
1174         {37,"lifeSafetyOperation"},
1175         {38,"subscribeCOVProperty"},
1176         {39,"getEventInformation"},
1177         {0, NULL}
1178 };
1179
1180 static const value_string
1181 BACnetPropertyStates [] = {
1182         {0,"boolean-value"},
1183         {1,"binary-value"},
1184         {2,"event-type"},
1185         {3,"polarity"},
1186         {4,"program-change"},
1187         {5,"program-state"},
1188         {6,"reason-for-halt"},
1189         {7,"reliability"},
1190         {8,"state"},
1191         {9,"system-status"},
1192         {10,"units"},
1193         {11,"unsigned-value"},
1194         {12,"life-safety-mode"},
1195         {13,"life-safety-state"},
1196         {0,NULL}
1197 /* Tag values 0-63 are reserved for definition by ASHRAE.
1198    Tag values of 64-254 may be used by others to accommodate
1199    vendor specific properties that have discrete or enumerated values,
1200    subject to the constraints described in Clause 23. */
1201 };
1202
1203 static const value_string
1204 BACnetProgramError [] = {
1205         {0,"normal"},
1206         {1,"load-failed"},
1207         {2,"internal"},
1208         {3,"program"},
1209         {4,"other"},
1210         {0,NULL}
1211 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
1212    Enumerated values 64-65535 may be used by others subject to
1213    the procedures and constraints described in Clause 23. */
1214 };
1215
1216 static const value_string
1217 BACnetProgramRequest [] = {
1218         {0,"ready"},
1219         {1,"load"},
1220         {2,"run"},
1221         {3,"halt"},
1222         {4,"restart"},
1223         {4,"unload"},
1224         {0,NULL}
1225 };
1226
1227 static const value_string
1228 BACnetProgramState [] = {
1229         {0,"idle"},
1230         {1,"loading"},
1231         {2,"running"},
1232         {3,"waiting"},
1233         {4,"halted"},
1234         {4,"unloading"},
1235         {0,NULL}
1236 };
1237
1238 static const value_string
1239 BACnetReinitializedStateOfDevice [] = {
1240         {0,"coldstart"},
1241         {1,"warmstart"},
1242         {2,"startbackup"},
1243         {3,"endbackup"},
1244         {4,"startrestore"},
1245         {5,"endrestore"},
1246         {6,"abortrestore"},
1247         {0,NULL}
1248 };
1249
1250 static const value_string
1251 BACnetPolarity [] = {
1252         {0,"normal"},
1253         {1,"reverse"},
1254         {0,NULL}
1255 };
1256
1257 static const value_string
1258 BACnetTagNames[] = {
1259         { 5, "Extended Value" },
1260         { 6, "Opening Tag" },
1261         { 7, "Closing Tag" },
1262         { 0, NULL }
1263 };
1264
1265 static const value_string
1266 BACnetReadRangeOptions[] = {
1267         { 3, "range byPosition" },
1268         { 4, "range byTime" },
1269         { 5, "range timeRange" },
1270         { 6, "range bySequenceNumber" },
1271         { 7, "range byTime" },
1272         { 0, NULL }
1273 };
1274
1275 static int proto_bacapp = -1;
1276 static int hf_bacapp_type = -1;
1277 static int hf_bacapp_pduflags = -1;
1278 static int hf_bacapp_SEG = -1;
1279 static int hf_bacapp_MOR = -1;
1280 static int hf_bacapp_SA = -1;
1281 static int hf_bacapp_response_segments = -1;
1282 static int hf_bacapp_max_adpu_size = -1;
1283 static int hf_bacapp_invoke_id = -1;
1284 static int hf_bacapp_objectType = -1;
1285 static int hf_bacapp_instanceNumber = -1;
1286 static int hf_bacapp_sequence_number = -1;
1287 static int hf_bacapp_window_size = -1;
1288 static int hf_bacapp_service = -1;
1289 static int hf_bacapp_NAK = -1;
1290 static int hf_bacapp_SRV = -1;
1291 static int hf_BACnetRejectReason = -1;
1292 static int hf_BACnetAbortReason = -1;
1293 static int hf_BACnetApplicationTagNumber = -1;
1294 static int hf_BACnetContextTagNumber = -1;
1295 static int hf_BACnetExtendedTagNumber = -1;
1296 static int hf_BACnetNamedTag = -1;
1297 static int hf_BACnetTagClass = -1;
1298 static int hf_BACnetCharacterSet = -1;
1299 static int hf_bacapp_tag = -1;
1300 static int hf_bacapp_tag_lvt = -1;
1301 static int hf_bacapp_tag_value8 = -1;
1302 static int hf_bacapp_tag_value16 = -1;
1303 static int hf_bacapp_tag_value32 = -1;
1304 static int hf_bacapp_tag_ProcessId = -1;
1305 static int hf_bacapp_tag_initiatingObjectType = -1;
1306 static int hf_bacapp_vpart = -1;
1307
1308 static int hf_bacapp_uservice = -1;
1309
1310
1311 static gint ett_bacapp = -1;
1312 static gint ett_bacapp_control = -1;
1313 static gint ett_bacapp_tag = -1;
1314 static gint ett_bacapp_list = -1;
1315 static gint ett_bacapp_value = -1;
1316
1317 static dissector_handle_t data_handle;
1318 static gint32 propertyIdentifier = -1;
1319 static guint32 object_type = 4096;
1320
1321 static guint8 bacapp_flags = 0;
1322 static guint8 bacapp_seq = 0;
1323
1324 /* Used when there are ranges of reserved and proprietary enumerations */
1325 static const char*
1326 val_to_split_str(guint32 val, guint32 split_val, const value_string *vs,
1327         const char *fmt, const char *split_fmt)
1328 {
1329         if (val < split_val)
1330                 return val_to_str(val, vs, fmt);
1331         else
1332                 return val_to_str(val, vs, split_fmt);
1333 }
1334
1335 /* from clause 20.2.1.3.2 Constructed Data */
1336 /* returns true if the extended value is used */
1337 static gboolean tag_is_extended_value(guint8 tag)
1338 {
1339         return (tag & 0x07) == 5;
1340 }
1341
1342 static gboolean tag_is_opening(guint8 tag)
1343 {
1344         return (tag & 0x07) == 6;
1345 }
1346
1347 static gboolean tag_is_closing(guint8 tag)
1348 {
1349         return (tag & 0x07) == 7;
1350 }
1351
1352 /* from clause 20.2.1.1 Class
1353    class bit shall be one for context specific tags */
1354 /* returns true if the tag is context specific */
1355 static gboolean tag_is_context_specific(guint8 tag)
1356 {
1357         return (tag & 0x08) != 0;
1358 }
1359
1360 static gboolean tag_is_extended_tag_number(guint8 tag)
1361 {
1362         return ((tag & 0xF0) == 0xF0);
1363 }
1364
1365 static guint32 object_id_type(guint32 object_identifier)
1366 {
1367         return ((object_identifier >> 22) & 0x3FF);
1368 }
1369
1370 static guint32 object_id_instance(guint32 object_identifier)
1371 {
1372         return (object_identifier & 0x3FFFFF);
1373 }
1374
1375 static guint
1376 fTagNo (tvbuff_t *tvb, guint offset)
1377 {
1378         return (guint)(tvb_get_guint8(tvb, offset) >> 4);
1379 }
1380
1381 static gboolean
1382 fUnsigned32 (tvbuff_t *tvb, guint offset, guint32 lvt, guint32 *val)
1383 {
1384         gboolean valid = TRUE;
1385
1386         switch (lvt) {
1387                 case 1:
1388                         *val = tvb_get_guint8(tvb, offset);
1389                         break;
1390                 case 2:
1391                         *val = tvb_get_ntohs(tvb, offset);
1392                         break;
1393                 case 3:
1394                         *val = tvb_get_ntoh24(tvb, offset);
1395                         break;
1396                 case 4:
1397                         *val = tvb_get_ntohl(tvb, offset);
1398                         break;
1399                 default:
1400                         valid = FALSE;
1401                         break;
1402         }
1403
1404         return valid;
1405 }
1406
1407 static gboolean
1408 fUnsigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, guint64 *val)
1409 {
1410         gboolean valid = FALSE;
1411         gint64 value = 0;
1412         guint8 data, i;
1413
1414         if (lvt && (lvt <= 8)) {
1415                 valid = TRUE;
1416                 data = tvb_get_guint8(tvb, offset);
1417                 for (i = 0; i < lvt; i++) {
1418                         data = tvb_get_guint8(tvb, offset+i);
1419                         value = (value << 8) + data;
1420                 }
1421                 *val = value;
1422         }
1423
1424         return valid;
1425 }
1426
1427 /* BACnet Signed Value uses 2's compliment notation, but with a twist:
1428    All signed integers shall be encoded in the smallest number of octets
1429    possible.  That is, the first octet of any multi-octet encoded value
1430    shall not be X'00' if the most significant bit (bit 7) of the second
1431    octet is 0, and the first octet shall not be X'FF' if the most
1432    significant bit of the second octet is 1. ASHRAE-135-2004-20.2.5 */
1433 static gboolean
1434 fSigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, gint64 *val)
1435 {
1436         gboolean valid = FALSE;
1437         gint64 value = 0;
1438         guint8 data, i;
1439
1440         /* we can only handle 7 bytes for a 64-bit value due to signed-ness */
1441         if (lvt && (lvt <= 7)) {
1442                 valid = TRUE;
1443                 data = tvb_get_guint8(tvb, offset);
1444                 if ((data & 0x80) != 0)
1445                         value = (-1 << 8) | data;
1446                 else
1447                         value = data;
1448                 for (i = 1; i < lvt; i++) {
1449                         data = tvb_get_guint8(tvb, offset+i);
1450                         value = (value << 8) + data;
1451                 }
1452                 *val = value;
1453         }
1454
1455         return valid;
1456 }
1457
1458 static guint
1459 fTagHeaderTree (tvbuff_t *tvb, proto_tree *tree, guint offset,
1460         guint8 *tag_no, guint8* tag_info, guint32 *lvt)
1461 {
1462         guint8 tag;
1463         guint8 value;
1464         guint tag_len = 1;
1465         guint lvt_len = 1; /* used for tree display of lvt */
1466         guint lvt_offset; /* used for tree display of lvt */
1467         proto_item *ti;
1468         proto_tree *subtree;
1469
1470         lvt_offset = offset;
1471         tag = tvb_get_guint8(tvb, offset);
1472         *tag_info = 0;
1473         *lvt = tag & 0x07;
1474     /* To solve the problem of lvt values of 6/7 being indeterminate - it */
1475     /* can mean open/close tag or length of 6/7 after the length is */
1476     /* computed below - store whole tag info, not just context bit. */
1477         if (tag_is_context_specific(tag)) *tag_info = tag & 0x0F;
1478         *tag_no = tag >> 4;
1479         if (tag_is_extended_tag_number(tag)) {
1480                 *tag_no = tvb_get_guint8(tvb, offset + tag_len++);
1481         }
1482         if (tag_is_extended_value(tag)) {       /* length is more than 4 Bytes */
1483                 lvt_offset += tag_len;
1484                 value = tvb_get_guint8(tvb, lvt_offset);
1485                 tag_len++;
1486                 if (value == 254) { /* length is encoded with 16 Bits */
1487                         *lvt = tvb_get_ntohs(tvb, lvt_offset+1);
1488                         tag_len += 2;
1489                         lvt_len += 2;
1490                 } else if (value == 255) { /* length is encoded with 32 Bits */
1491                         *lvt = tvb_get_ntohl(tvb, lvt_offset+1);
1492                         tag_len += 4;
1493                         lvt_len += 4;
1494                 } else
1495                         *lvt = value;
1496         }
1497         if (tree)
1498         {
1499                 if (tag_is_closing(tag) || tag_is_opening(tag))
1500                         ti = proto_tree_add_text(tree, tvb, offset, tag_len,
1501                                 "%s: %u", match_strval(
1502                                         tag & 0x07, BACnetTagNames),
1503                                 *tag_no);
1504                 else if (tag_is_context_specific(tag)) {
1505                         ti = proto_tree_add_text(tree, tvb, offset, tag_len,
1506                                 "Context Tag: %u, Length/Value/Type: %u",
1507                                 *tag_no, *lvt);
1508                 } else
1509                         ti = proto_tree_add_text(tree, tvb, offset, tag_len,
1510                                 "Application Tag: %s, Length/Value/Type: %u",
1511                                 val_to_str(*tag_no,
1512                                         BACnetApplicationTagNumber,
1513                                         ASHRAE_Reserved_Fmt),
1514                                         *lvt);
1515                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1516                 /* details if needed */
1517                 proto_tree_add_item(subtree, hf_BACnetTagClass, tvb, offset, 1, FALSE);
1518                 if (tag_is_extended_tag_number(tag)) {
1519                         proto_tree_add_uint_format(subtree,
1520                                         hf_BACnetContextTagNumber,
1521                                         tvb, offset, 1, tag,
1522                                         "Extended Tag Number");
1523                         proto_tree_add_item(subtree,
1524                                 hf_BACnetExtendedTagNumber,
1525                                 tvb, offset + 1, 1, FALSE);
1526                 } else {
1527                         if (tag_is_context_specific(tag))
1528                                 proto_tree_add_item(subtree,
1529                                         hf_BACnetContextTagNumber,
1530                                         tvb, offset, 1, FALSE);
1531                         else
1532                                 proto_tree_add_item(subtree,
1533                                         hf_BACnetApplicationTagNumber,
1534                                         tvb, offset, 1, FALSE);
1535                 }
1536                 if (tag_is_closing(tag) || tag_is_opening(tag))
1537                         proto_tree_add_item(subtree,
1538                                 hf_BACnetNamedTag,
1539                                 tvb, offset, 1, FALSE);
1540                 else if (tag_is_extended_value(tag)) {
1541                         proto_tree_add_item(subtree,
1542                                 hf_BACnetNamedTag,
1543                                 tvb, offset, 1, FALSE);
1544                         proto_tree_add_uint(subtree, hf_bacapp_tag_lvt,
1545                                 tvb, lvt_offset, lvt_len, *lvt);
1546                 } else
1547                         proto_tree_add_uint(subtree, hf_bacapp_tag_lvt,
1548                                 tvb, lvt_offset, lvt_len, *lvt);
1549         }
1550
1551         return tag_len;
1552 }
1553
1554 static guint
1555 fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* tag_info,
1556         guint32 *lvt)
1557 {
1558         return fTagHeaderTree (tvb, NULL, offset, tag_no, tag_info, lvt);
1559 }
1560
1561 static guint
1562 fNullTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1563 {
1564         guint8 tag_no, tag_info;
1565         guint32 lvt;
1566         proto_item *ti;
1567         proto_tree *subtree;
1568
1569         ti = proto_tree_add_text(tree, tvb, offset, 1, "%sNULL", label);
1570         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1571         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1572
1573         return offset + 1;
1574 }
1575
1576 static guint
1577 fBooleanTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1578 {
1579         guint8 tag_no, tag_info;
1580         guint32 lvt = 0;
1581         guint tag_len;
1582         proto_item *ti;
1583         proto_tree *subtree;
1584         guint bool_len = 1;
1585
1586         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1587         if (tag_info && lvt == 1)
1588         {
1589                 lvt = tvb_get_guint8(tvb, offset+1);
1590                 ++bool_len;
1591         }
1592
1593         ti = proto_tree_add_text(tree, tvb, offset, bool_len,
1594                 "%s%s", label, lvt == 0 ? "FALSE" : "TRUE");
1595         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1596         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1597
1598         return offset + bool_len;
1599 }
1600
1601 static guint
1602 fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1603 {
1604         guint64 val = 0;
1605         guint8 tag_no, tag_info;
1606         guint32 lvt;
1607     guint tag_len;
1608         proto_item *ti;
1609         proto_tree *subtree;
1610
1611         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1612         /* only support up to an 8 byte (64-bit) integer */
1613         if (fUnsigned64 (tvb, offset + tag_len, lvt, &val))
1614                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1615                         "%s(Unsigned) %" G_GINT64_MODIFIER "u", label, val);
1616         else
1617                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1618                         "%s - %u octets (Unsigned)", label, lvt);
1619         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1620         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1621
1622         return offset+tag_len+lvt;
1623 }
1624
1625 /* set split_val to zero when not needed */
1626 static guint
1627 fEnumeratedTagSplit (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
1628         const value_string *vs, guint32 split_val)
1629 {
1630         guint32 val = 0;
1631         guint8 tag_no, tag_info;
1632         guint32 lvt;
1633         guint tag_len;
1634         proto_item *ti;
1635         proto_tree *subtree;
1636
1637         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1638         /* only support up to a 4 byte (32-bit) enumeration */
1639         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val)) {
1640                 if (vs)
1641                         ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1642                                 "%s %s", label, val_to_split_str(val, split_val, vs,
1643                                 ASHRAE_Reserved_Fmt,Vendor_Proprietary_Fmt));
1644                 else
1645                         ti =proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1646                                 "%s %u", label, val);
1647         } else {
1648                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1649                         "%s - %u octets (enumeration)", label, lvt);
1650         }
1651         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1652         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1653
1654         return offset+tag_len+lvt;
1655 }
1656
1657 static guint
1658 fEnumeratedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
1659         const value_string *vs)
1660 {
1661         return fEnumeratedTagSplit (tvb, tree, offset, label, vs, 0);
1662 }
1663
1664 static guint
1665 fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1666 {
1667         gint64 val = 0;
1668         guint8 tag_no, tag_info;
1669         guint32 lvt;
1670         guint tag_len;
1671         proto_item *ti;
1672         proto_tree *subtree;
1673
1674         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1675         if (fSigned64 (tvb, offset + tag_len, lvt, &val))
1676                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1677                         "%s(Signed) %" G_GINT64_MODIFIER "d", label, val);
1678         else
1679                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1680                         "%s - %u octets (Signed)", label, lvt);
1681         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1682         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1683
1684         return offset+tag_len+lvt;
1685 }
1686
1687 static guint
1688 fRealTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1689 {
1690         guint8 tag_no, tag_info;
1691         guint32 lvt;
1692         guint tag_len;
1693         gfloat f_val;
1694         proto_item *ti;
1695         proto_tree *subtree;
1696
1697         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
1698         f_val = tvb_get_ntohieee_float(tvb, offset+tag_len);
1699         ti = proto_tree_add_text(tree, tvb, offset, 4+tag_len,
1700                 "%s%f (Real)", label, f_val);
1701         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1702         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1703
1704         return offset+tag_len+4;
1705 }
1706
1707 static guint
1708 fDoubleTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1709 {
1710         guint8 tag_no, tag_info;
1711         guint32 lvt;
1712         guint tag_len;
1713         gdouble d_val;
1714         proto_item *ti;
1715         proto_tree *subtree;
1716
1717         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
1718         d_val = tvb_get_ntohieee_double(tvb, offset+tag_len);
1719         ti = proto_tree_add_text(tree, tvb, offset, 8+tag_len,
1720                 "%s%lf (Double)", label, d_val);
1721         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1722         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1723
1724         return offset+tag_len+8;
1725 }
1726
1727 static guint
1728 fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset)
1729 {
1730         guint32 val = 0, lvt;
1731         guint8 tag_no, tag_info;
1732         proto_item *ti;
1733         proto_tree *subtree;
1734         guint tag_len;
1735
1736         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1737         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val))
1738                 ti = proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId,
1739                         tvb, offset, lvt+tag_len, val);
1740         else
1741                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1742                         "Process Identifier - %u octets (Signed)", lvt);
1743         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1744         offset += tag_len + lvt;
1745
1746         return offset;
1747 }
1748
1749 static guint
1750 fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1751 {
1752         guint32 val = 0, lvt;
1753         guint8 tag_no, tag_info;
1754         proto_item *ti;
1755         proto_tree *subtree;
1756         guint tag_len;
1757
1758         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1759         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val))
1760                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1761                 "%s (hh.mm.ss): %d.%02d.%02d%s",
1762                 label,
1763                 (val / 3600), ((val % 3600) / 60), (val % 60),
1764                 val == 0 ? " (indefinite)" : "");
1765         else
1766                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1767                         "%s - %u octets (Signed)", label, lvt);
1768         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1769         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1770
1771         return offset+tag_len+lvt;
1772 }
1773
1774 static guint
1775 fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset)
1776 {
1777         guint32 month, weekOfMonth, dayOfWeek;
1778         guint8 tag_no, tag_info;
1779         guint32 lvt;
1780         guint tag_len;
1781         proto_item *ti;
1782         proto_tree *subtree;
1783
1784         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1785         month = tvb_get_guint8(tvb, offset+tag_len);
1786         weekOfMonth = tvb_get_guint8(tvb, offset+tag_len+1);
1787         dayOfWeek = tvb_get_guint8(tvb, offset+tag_len+2);
1788         ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s %s, %s",
1789                         val_to_str(month, months, "month (%d) not found"),
1790                         val_to_str(weekOfMonth, weekofmonth, "week of month (%d) not found"),
1791                         val_to_str(dayOfWeek, days, "day of week (%d) not found"));
1792         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1793         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1794
1795         return offset+tag_len+lvt;
1796 }
1797
1798 static guint
1799 fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1800 {
1801         guint32 year, month, day, weekday;
1802         guint8 tag_no, tag_info;
1803         guint32 lvt;
1804         guint tag_len;
1805         proto_item *ti;
1806         proto_tree *subtree;
1807
1808         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1809         year = tvb_get_guint8(tvb, offset+tag_len);
1810         month = tvb_get_guint8(tvb, offset+tag_len+1);
1811         day = tvb_get_guint8(tvb, offset+tag_len+2);
1812         weekday = tvb_get_guint8(tvb, offset+tag_len+3);
1813         if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
1814         {
1815                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1816                         "%sany", label);
1817         }
1818         else if (year != 255)
1819         {
1820                 year += 1900;
1821                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1822                         "%s%s %d, %d, (Day of Week = %s)",
1823                         label, val_to_str(month,
1824                                 months,
1825                                 "month (%d) not found"),
1826                         day, year, val_to_str(weekday,
1827                                 days,
1828                                 "(%d) not found"));
1829         }
1830         else
1831         {
1832                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1833                         "%s%s %d, any year, (Day of Week = %s)",
1834                         label, val_to_str(month, months, "month (%d) not found"),
1835                         day, val_to_str(weekday, days, "(%d) not found"));
1836         }
1837         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1838         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1839
1840         return offset+tag_len+lvt;
1841 }
1842
1843 static guint
1844 fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1845 {
1846         guint32 hour, minute, second, msec, lvt;
1847         guint8 tag_no, tag_info;
1848         guint tag_len;
1849         proto_item *ti;
1850         proto_tree *subtree;
1851
1852         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1853         hour = tvb_get_guint8(tvb, offset+tag_len);
1854         minute = tvb_get_guint8(tvb, offset+tag_len+1);
1855         second = tvb_get_guint8(tvb, offset+tag_len+2);
1856         msec = tvb_get_guint8(tvb, offset+tag_len+3);
1857         if ((hour == 255) && (minute == 255) && (second == 255) && (msec == 255))
1858                 ti = proto_tree_add_text(tree, tvb, offset,
1859                         lvt+tag_len, "%sany", label);
1860         else
1861                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1862                         "%s%d:%02d:%02d.%d %s = %02d:%02d:%02d.%d",
1863                         label,
1864                         hour > 12 ? hour - 12 : hour,
1865                         minute, second, msec,
1866                         hour > 12 ? "P.M." : "A.M.",
1867                         hour, minute, second, msec);
1868         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1869         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1870
1871         return offset+tag_len+lvt;
1872 }
1873
1874 static guint
1875 fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1876 {
1877         proto_tree *subtree = tree;
1878         proto_item *tt;
1879
1880         if (label != NULL) {
1881                 tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", label);
1882                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
1883         }
1884         offset = fDate (tvb,subtree,offset,"Date: ");
1885         return fTime (tvb,subtree,offset,"Time: ");
1886 }
1887
1888 static guint
1889 fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
1890 {
1891         guint lastoffset = 0;
1892         guint8 tag_no, tag_info;
1893         guint32 lvt;
1894
1895         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
1896                 lastoffset = offset;
1897                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1898                 if (tag_is_closing(tag_info)) {   /* closing Tag, but not for me */
1899                         return offset;
1900                 }
1901                 offset = fTime    (tvb,tree,offset,"Time: ");
1902                 offset = fApplicationTypes(tvb, tree, offset, "Value: ");
1903         }
1904         return offset;
1905 }
1906
1907 static guint
1908 fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset)
1909 {
1910     guint8 tag_no, tag_info;
1911     guint32 lvt;
1912
1913         switch (fTagNo(tvb, offset)) {
1914         case 0: /* Date */
1915                 offset = fDate    (tvb, tree, offset, "Date: ");
1916                 break;
1917         case 1: /* dateRange */
1918         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
1919                 offset = fDateRange (tvb, tree, offset);
1920         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
1921                 break;
1922         case 2: /* BACnetWeekNDay */
1923                 offset = fWeekNDay (tvb, tree, offset);
1924                 break;
1925         default:
1926                 return offset;
1927                 break;
1928         }
1929
1930         return offset;
1931 }
1932
1933 static guint
1934 fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset)
1935 {
1936         guint8 tag_no = 0, tag_info = 0;
1937         guint32 lvt = 0;
1938
1939         if (tvb_length_remaining(tvb, offset) > 0) {    /* don't loop, it's a CHOICE */
1940                 switch (fTagNo(tvb, offset)) {
1941                 case 0: /* time */
1942                         offset = fTime (tvb, tree, offset, "timestamp: ");
1943                         break;
1944                 case 1: /* sequenceNumber */
1945                         offset = fUnsignedTag (tvb, tree, offset, "sequence Number: ");
1946                         break;
1947                 case 2: /* dateTime */
1948                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
1949                         offset = fDateTime (tvb, tree, offset, "timestamp: ");
1950                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
1951                         break;
1952                 default:
1953                         return offset;
1954                         break;
1955                 }
1956         }
1957         return offset;
1958 }
1959
1960 #if 0
1961 static guint
1962 fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
1963 {
1964         guint lastoffset = 0;
1965
1966         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
1967                 lastoffset = offset;
1968
1969                 switch (fTagNo(tvb, offset)) {
1970                 case 0: /* setpointReference */
1971                         offset = fBACnetObjectPropertyReference (tvb,tree,offset);
1972                         break;
1973                 default:
1974                         return offset;
1975                         break;
1976                 }
1977         }
1978         return offset;
1979 }
1980 #endif
1981
1982 #if 0
1983 static guint
1984 fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset)
1985 {
1986         if (tvb_length_remaining(tvb, offset) > 0) {
1987         offset = fApplicationTypes(tvb,tree,offset, "increment: ");
1988     }
1989     return offset;
1990 }
1991
1992 static guint
1993 fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset)
1994 {
1995         if (tvb_length_remaining(tvb, offset) > 0) {
1996                 offset = fApplicationTypesEnumerated(tvb,tree,offset,
1997                         "valid Days: ", days);
1998                 offset = fTime (tvb,tree,offset,"from time: ");
1999                 offset = fTime (tvb,tree,offset,"to time: ");
2000                 offset = fRecipient (tvb,tree,offset);
2001                 offset = fProcessId (tvb,tree,offset);
2002                 offset = fApplicationTypes (tvb,tree,offset,
2003                         "issue confirmed notifications: ");
2004                 offset = fApplicationTypesEnumerated (tvb,tree,offset,
2005                         "transitions: ", BACnetEventTransitionBits);
2006         }
2007         return offset;
2008 }
2009
2010 #endif
2011
2012 static guint
2013 fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, guint32 lvt)
2014 {
2015         gchar *tmp;
2016     guint start = offset;
2017         guint8 tag_no, tag_info;
2018     proto_tree* subtree = tree;
2019     proto_item* ti = 0;
2020
2021         offset += fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2022
2023         if (lvt > 0)
2024     {
2025             tmp = tvb_bytes_to_str(tvb, offset, lvt);
2026             ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s %s", label, tmp);
2027                 offset += lvt;
2028     }
2029
2030         if (ti)
2031         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2032
2033     fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt);
2034
2035         return offset;
2036 }
2037
2038 static guint
2039 fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset)
2040 {
2041         guint8 tag_no, tag_info;
2042         guint32 lvt;
2043     guint offs;
2044
2045         offset = fUnsignedTag (tvb, tree, offset, "network-number");
2046         offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2047         if (lvt == 0) {
2048                 proto_tree_add_text(tree, tvb, offset, offs, "mac-address: broadcast");
2049                 offset += offs;
2050         } else
2051                 offset = fOctetString (tvb, tree, offset, "mac-address: ", lvt);
2052         return offset;
2053 }
2054
2055 static guint
2056 fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset)
2057 {
2058         offset = fOctetString (tvb,tree,offset,"session key: ", 8);
2059         return fAddress (tvb,tree,offset);
2060 }
2061
2062 static guint
2063 fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
2064 {
2065         guint8  tag_no, tag_info;
2066         guint32 lvt;
2067         guint tag_length;
2068         proto_item *ti;
2069         proto_tree *subtree;
2070         guint32 object_id;
2071
2072         tag_length = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
2073         object_id = tvb_get_ntohl(tvb,offset+tag_length);
2074         object_type = object_id_type(object_id);
2075         ti = proto_tree_add_text(tree, tvb, offset, tag_length + 4,
2076                 "ObjectIdentifier: %s, %u",
2077                 val_to_split_str(object_type,
2078                         128,
2079                         BACnetObjectType,
2080                         ASHRAE_Reserved_Fmt,
2081                         Vendor_Proprietary_Fmt),
2082                 object_id_instance(object_id));
2083         /* here are the details of how we arrived at the above text */
2084         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2085         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2086         offset += tag_length;
2087         proto_tree_add_item(subtree, hf_bacapp_objectType, tvb, offset, 4, FALSE);
2088         proto_tree_add_item(subtree, hf_bacapp_instanceNumber, tvb, offset, 4, FALSE);
2089         offset += 4;
2090
2091         return offset;
2092 }
2093
2094 static guint
2095 fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset)
2096 {
2097         guint8  tag_no, tag_info;
2098         guint32 lvt;
2099
2100         fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
2101         if (tag_no < 2) {
2102                 if (tag_no == 0) { /* device */
2103                         offset = fObjectIdentifier (tvb, tree, offset);
2104                 }
2105                 else {  /* address */
2106                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
2107                         offset = fAddress (tvb, tree, offset);
2108                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
2109                 }
2110         }
2111         return offset;
2112 }
2113
2114 static guint
2115 fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset)
2116 {
2117         guint lastoffset = 0;
2118         guint8  tag_no, tag_info;
2119         guint32 lvt;
2120
2121         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2122                 lastoffset = offset;
2123
2124                 switch (fTagNo(tvb, offset)) {
2125                 case 0: /* recipient */
2126                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
2127                         offset = fRecipient (tvb, tree, offset);
2128                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
2129                         break;
2130                 case 1: /* processId */
2131                         offset = fProcessId (tvb, tree, offset);
2132                         lastoffset = offset;
2133                         break;
2134                 default:
2135                         break;
2136                 }
2137         }
2138         return offset;
2139 }
2140
2141 static guint
2142 fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset)
2143 {
2144         offset = fObjectIdentifier (tvb, tree, offset);
2145         return fAddress (tvb, tree, offset);
2146 }
2147
2148 static guint
2149 fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset)
2150 {
2151         guint lastoffset = 0;
2152         guint8 tag_no, tag_info;
2153         guint32 lvt;
2154         proto_tree *subtree = tree;
2155         proto_item *tt;
2156
2157         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2158                 lastoffset = offset;
2159                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2160                 if (tag_is_closing(tag_info)) {
2161                         offset += fTagHeaderTree (tvb, subtree, offset,
2162                                 &tag_no, &tag_info, &lvt);
2163                         subtree = tree;
2164                         continue;
2165                 }
2166                 switch (tag_no) {
2167
2168                 case 0: /* deviceIdentifier */
2169                         offset = fObjectIdentifier (tvb, subtree, offset);
2170                         break;
2171                 case 1: /* objectIdentifier */
2172                         offset = fObjectIdentifier (tvb, subtree, offset);
2173                         break;
2174                 case 2: /* propertyIdentifier */
2175                         offset = fPropertyIdentifier (tvb, subtree, offset);
2176                         break;
2177                 case 3: /* propertyArrayIndex */
2178                         offset = fUnsignedTag (tvb,subtree,offset,"Property Array Index: ");
2179                         break;
2180                 case 4: /* propertyValue */
2181                         if (tag_is_opening(tag_info)) {
2182                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
2183                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2184                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2185                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2186                                 break;
2187                         }
2188                         FAULT;
2189                         break;
2190                 case 5: /* priority */
2191                         offset = fUnsignedTag (tvb,subtree,offset,"Priority: ");
2192                         break;
2193                 case 6: /* postDelay */
2194                         offset = fUnsignedTag (tvb,subtree,offset,"Post Delay: ");
2195                         break;
2196                 case 7: /* quitOnFailure */
2197                         offset = fBooleanTag(tvb, subtree, offset,
2198                                 "Quit On Failure: ");
2199                         break;
2200                 case 8: /* writeSuccessful */
2201                         offset = fBooleanTag(tvb, subtree, offset,
2202                                 "Write Successful: ");
2203                         break;
2204                 default:
2205                         return offset;
2206                 }
2207         }
2208         return offset;
2209 }
2210
2211 static guint
2212 fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset)
2213 {
2214         return fActionCommand (tvb,tree,offset);
2215 }
2216
2217 static guint
2218 fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
2219 {
2220         guint8 tag_no, tag_info;
2221         guint32 lvt;
2222         guint tag_len;
2223         proto_item *ti;
2224         proto_tree *subtree;
2225
2226         propertyIdentifier = 0; /* global Variable */
2227         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2228         if (fUnsigned32 (tvb, offset+tag_len, lvt, (guint32 *)&propertyIdentifier))
2229                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
2230                         "property Identifier: %s",
2231                         val_to_split_str(propertyIdentifier, 512,
2232                                 BACnetPropertyIdentifier,
2233                                 ASHRAE_Reserved_Fmt,
2234                                 Vendor_Proprietary_Fmt));
2235         else
2236                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
2237                 "Property Identifier - %u octets", lvt);
2238         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2239         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2240
2241         return offset+tag_len+lvt;
2242 }
2243
2244 static guint
2245 fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2246 {
2247         guint8 tag_no, tag_info, character_set;
2248         guint32 lvt, l;
2249         size_t inbytesleft, outbytesleft = 512;
2250         guint offs, extra = 1;
2251         guint8 *str_val;
2252         guint8 bf_arr[512], *out = &bf_arr[0];
2253         proto_item *ti;
2254         proto_tree *subtree;
2255     guint start = offset;
2256
2257         if (tvb_length_remaining(tvb, offset) > 0) {
2258
2259                 offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2260
2261                 character_set = tvb_get_guint8(tvb, offset+offs);
2262         /* Account for code page if DBCS */
2263         if (character_set == 1)
2264         {
2265             extra = 3;
2266         }
2267         offset += (offs+extra);
2268         lvt -= (extra);
2269
2270                 do {
2271                         l = inbytesleft = min(lvt, 255);
2272                         /*
2273                          * XXX - are we guaranteed that these encoding
2274                          * names correspond, on *all* platforms with
2275                          * iconv(), to the encodings we want?
2276                          * If not (and perhaps even if so), we should
2277                          * perhaps have our own iconv() implementation,
2278                          * with a different name, so that we control the
2279                          * encodings it supports and the names of those
2280                          * encodings.
2281                          *
2282                          * We should also handle that in the general
2283                          * string handling code, rather than making it
2284                          * specific to the BACAPP dissector, as many
2285                          * other dissectors need to handle various
2286                          * character encodings.
2287                          */
2288                         str_val = tvb_get_ephemeral_string(tvb, offset, l);
2289                         /** this decoding may be not correct for multi-byte characters, Lka */
2290                         switch (character_set) {
2291                         case 0x00:      /* ANSI_X3.4 */
2292                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ANSI_X3.4");
2293                                 break;
2294                         case 1: /* IBM/MICROSOFT DBCS */
2295                                 out = str_val;
2296                                 break;
2297                         case 2: /* JIS C 6226 */
2298                                 out = str_val;
2299                                 break;
2300                         case 3: /* UCS-4 */
2301                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-4BE");
2302                                 break;
2303                         case 4: /* UCS-2 */
2304                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-2BE");
2305                                 break;
2306                         case 5: /* ISO8859-1 */
2307                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ISO8859-1");
2308                                 break;
2309                         default:
2310                                 out = str_val;
2311                                 break;
2312                         }
2313                         ti = proto_tree_add_text(tree, tvb, offset, l, "%s'%s'", label, out);
2314                         lvt-=l;
2315                         offset+=l;
2316                 } while (lvt > 0);
2317
2318                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2319
2320         fTagHeaderTree (tvb, subtree, start, &tag_no, &tag_info, &lvt);
2321                 proto_tree_add_item(subtree, hf_BACnetCharacterSet, tvb, start+offs, 1, FALSE);
2322         if (character_set == 1)
2323         {
2324             proto_tree_add_text(subtree, tvb, start+offs+1, 2, "Code Page: %d", tvb_get_ntohs(tvb, start+offs+1));
2325         }
2326         }
2327         return offset;
2328 }
2329
2330 static guint
2331 fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
2332         const value_string *src)
2333 {
2334         guint8 tag_no, tag_info, tmp;
2335         gint j, unused, skip;
2336         guint offs;
2337         guint32 lvt, i, numberOfBytes;
2338         guint8 bf_arr[256];
2339
2340         offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2341         numberOfBytes = lvt-1; /* Ignore byte for unused bit count */
2342         offset+=offs;
2343         unused = tvb_get_guint8(tvb, offset); /* get the unused Bits */
2344         skip = 0;
2345         for (i = 0; i < numberOfBytes; i++) {
2346                 tmp = tvb_get_guint8(tvb, (offset)+i+1);
2347                 if (i == numberOfBytes-1) { skip = unused; }
2348                 for (j = 0; j < 8-skip; j++) {
2349                         if (src != NULL) {
2350                                 if (tmp & (1 << (7 - j)))
2351                                         proto_tree_add_text(tree, tvb,
2352                                                 offset+i+1, 1,
2353                                                 "%s%s = TRUE",
2354                                                 label,
2355                                                 val_to_str((guint) (i*8 +j),
2356                                                         src,
2357                                                         ASHRAE_Reserved_Fmt));
2358                                 else
2359                                         proto_tree_add_text(tree, tvb,
2360                                                 offset+i+1, 1,
2361                                                 "%s%s = FALSE",
2362                                                 label,
2363                                                 val_to_str((guint) (i*8 +j),
2364                                                         src,
2365                                                         ASHRAE_Reserved_Fmt));
2366
2367                         } else {
2368                                 bf_arr[min(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
2369                         }
2370                 }
2371         }
2372
2373         if (src == NULL)
2374         {
2375                 bf_arr[min(255,numberOfBytes*8-unused)] = 0;
2376                 proto_tree_add_text(tree, tvb, offset, lvt, "%sB'%s'", label, bf_arr);
2377         }
2378
2379         offset+=lvt;
2380
2381         return offset;
2382 }
2383
2384 static guint
2385 fBitStringTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2386 {
2387         return fBitStringTagVS (tvb, tree, offset, label, NULL);
2388 }
2389
2390 /* handles generic application types, as well as enumerated and enumerations
2391    with reserved and proprietarty ranges (split) */
2392 static guint
2393 fApplicationTypesEnumeratedSplit (tvbuff_t *tvb, proto_tree *tree, guint offset,
2394         const gchar *label, const value_string *src, guint32 split_val)
2395 {
2396         guint8 tag_no, tag_info;
2397         guint32 lvt;
2398         guint tag_len;
2399
2400         if (tvb_length_remaining(tvb, offset) > 0) {
2401
2402                 tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2403                 if (!tag_is_context_specific(tag_info))
2404                 {
2405                         switch (tag_no) {
2406                                 case 0: /** NULL 20.2.2 */
2407                                         offset = fNullTag(tvb, tree, offset, label);
2408                                         break;
2409                                 case 1: /** BOOLEAN 20.2.3 */
2410                                         offset = fBooleanTag(tvb, tree, offset, label);
2411                                         break;
2412                                 case 2: /** Unsigned Integer 20.2.4 */
2413                                         offset = fUnsignedTag(tvb, tree, offset, label);
2414                                         break;
2415                                 case 3: /** Signed Integer 20.2.5 */
2416                                         offset = fSignedTag(tvb, tree, offset, label);
2417                                         break;
2418                                 case 4: /** Real 20.2.6 */
2419                                         offset = fRealTag(tvb, tree, offset, label);
2420                                         break;
2421                                 case 5: /** Double 20.2.7 */
2422                                         offset = fDoubleTag(tvb, tree, offset, label);
2423                                         break;
2424                                 case 6: /** Octet String 20.2.8 */
2425                                         offset = fOctetString (tvb, tree, offset, label, lvt);
2426                                         break;
2427                                 case 7: /** Character String 20.2.9 */
2428                                         offset = fCharacterString (tvb,tree,offset,label);
2429                                         break;
2430                                 case 8: /** Bit String 20.2.10 */
2431                                         offset = fBitStringTagVS (tvb, tree, offset, label, src);
2432                                         break;
2433                                 case 9: /** Enumerated 20.2.11 */
2434                                         offset = fEnumeratedTagSplit (tvb, tree, offset, label, src, split_val);
2435                                         break;
2436                                 case 10: /** Date 20.2.12 */
2437                                         offset = fDate (tvb, tree, offset, label);
2438                                         break;
2439                                 case 11: /** Time 20.2.13 */
2440                                         offset = fTime (tvb, tree, offset, label);
2441                                         break;
2442                                 case 12: /** BACnetObjectIdentifier 20.2.14 */
2443                                         offset = fObjectIdentifier (tvb, tree, offset);
2444                                         break;
2445                                 case 13: /* reserved for ASHRAE */
2446                                 case 14:
2447                                 case 15:
2448                                         proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s'reserved for ASHRAE'", label);
2449                                         offset+=lvt+tag_len;
2450                                         break;
2451                                 default:
2452                                         break;
2453                         }
2454
2455                 }
2456         }
2457         return offset;
2458 }
2459
2460 static guint
2461 fApplicationTypesEnumerated (tvbuff_t *tvb, proto_tree *tree, guint offset,
2462         const gchar *label, const value_string *vs)
2463 {
2464   return fApplicationTypesEnumeratedSplit(tvb, tree, offset, label, vs, 0);
2465 }
2466
2467 static guint
2468 fApplicationTypes (tvbuff_t *tvb, proto_tree *tree, guint offset,
2469         const gchar *label)
2470 {
2471   return fApplicationTypesEnumeratedSplit(tvb, tree, offset, label, NULL, 0);
2472 }
2473
2474 static guint
2475 fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2476 {
2477         guint8 tag_no, tag_info;
2478         guint32 lvt;
2479         guint tag_len;
2480         proto_item *ti;
2481         proto_tree *subtree;
2482         gint tvb_len;
2483
2484         (void)label;
2485         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
2486         /* cap the the suggested length in case of bad data */
2487         tvb_len = tvb_length_remaining(tvb, offset+tag_len);
2488         if ((tvb_len >= 0) && ((guint32)tvb_len < lvt))
2489         {
2490                 lvt = tvb_len;
2491         }
2492         ti = proto_tree_add_text(tree, tvb, offset+tag_len, lvt,
2493                 "Context Value (as %u DATA octets)", lvt);
2494
2495         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2496         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2497
2498         return offset + tag_len + lvt;
2499 }
2500
2501 static guint
2502 fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset)
2503 {
2504         guint8 tag_no, tag_info;
2505         guint32 lvt;
2506         guint lastoffset = 0, depth = 0;
2507         char ar[256];
2508
2509         if (propertyIdentifier >= 0)
2510         {
2511                 g_snprintf (ar, sizeof(ar), "%s: ",
2512                         val_to_split_str(propertyIdentifier, 512,
2513                                 BACnetPropertyIdentifier,
2514                                 ASHRAE_Reserved_Fmt,
2515                                 Vendor_Proprietary_Fmt));
2516         }
2517         else
2518         {
2519                 g_snprintf (ar, sizeof(ar), "Abstract Type: ");
2520         }
2521         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2522                 lastoffset = offset;
2523                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2524                 if (tag_is_closing(tag_info)) { /* closing tag, but not for me */
2525                         if (depth <= 0) return offset;
2526                 }
2527
2528                 /* Application Tags */
2529                 switch (propertyIdentifier) {
2530                 case 2: /* BACnetActionList */
2531                         offset = fActionList (tvb,tree,offset);
2532                         break;
2533                 case 30: /* BACnetAddressBinding */
2534                         offset = fAddressBinding (tvb,tree,offset);
2535                         break;
2536                 case 55: /* list-of-session-keys */
2537                         fSessionKey (tvb, tree, offset);
2538                         break;
2539                 case 79: /* object-type */
2540                 case 96: /* protocol-object-types-supported */
2541                         offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, ar,
2542                                 BACnetObjectType, 128);
2543                         break;
2544                 case 97: /* Protocol-Services-Supported */
2545                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar,
2546                                 BACnetServicesSupported);
2547                         break;
2548                 case 107: /* segmentation-supported */
2549                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar,
2550                                 BACnetSegmentation);
2551                         break;
2552                 case 111: /* Status-Flags */
2553                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar,
2554                                 BACnetStatusFlags);
2555                         break;
2556                 case 112: /* System-Status */
2557                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar,
2558                                 BACnetDeviceStatus);
2559                         break;
2560                 case 117: /* units */
2561                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar,
2562                                 BACnetEngineeringUnits);
2563                         break;
2564                 case 87:        /* priority-array */
2565                         offset = fPriorityArray (tvb, tree, offset);
2566                         break;
2567                 case 38:        /* exception-schedule */
2568                         if (object_type < 128)
2569                         {
2570                                 offset = fSpecialEvent (tvb,tree,offset);
2571                         }
2572                         break;
2573                 case 123:       /* weekly-schedule */
2574                         if (object_type < 128)
2575                         {
2576                                 offset = fWeeklySchedule (tvb,tree,offset);
2577                         }
2578                         break;
2579                 case 159: /* member-of */
2580                 case 165: /* zone-members */
2581                         fDeviceObjectReference (tvb, tree, offset);
2582                         break;
2583                 default:
2584                         if (tag_info)
2585                         {
2586                                 if (tag_is_opening(tag_info))
2587                                 {
2588                                         ++depth;
2589                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
2590                                 }
2591                                 else if (tag_is_closing(tag_info))
2592                                 {
2593                                         --depth;
2594                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
2595                                 }
2596                                 else
2597                                 {
2598                                         offset = fContextTaggedValue(tvb, tree, offset, ar);
2599                                 }
2600                         }
2601                         else
2602                         {
2603                                 offset = fApplicationTypes (tvb, tree, offset, ar);
2604                         }
2605                         break;
2606                 }
2607         }
2608         return offset;
2609
2610 }
2611
2612 static guint
2613 fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 tagoffset)
2614 {
2615         guint lastoffset = offset;
2616         proto_item *tt;
2617         proto_tree *subtree;
2618         guint8 tag_no, tag_info;
2619         guint32 lvt;
2620
2621         offset = fPropertyReference(tvb, tree, offset, tagoffset, 0);
2622         if (offset > lastoffset)
2623         {
2624                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2625                 if (tag_no == tagoffset+2) {  /* Value - might not be present in ReadAccessResult */
2626                         if (tag_is_opening(tag_info)) {
2627                                 tt = proto_tree_add_text(tree, tvb, offset, 1, "propertyValue");
2628                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2629                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2630                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2631                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2632                         }
2633                 }
2634         }
2635         return offset;
2636 }
2637
2638 static guint
2639 fBACnetPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
2640 {
2641         guint lastoffset = 0;
2642         guint8 tag_no, tag_info;
2643         guint32 lvt;
2644
2645         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2646                 lastoffset = offset;
2647                 offset = fPropertyValue(tvb, tree, offset, 0);
2648                 if (offset > lastoffset)
2649                 {
2650                         /* detect optional priority
2651                         by looking to see if the next tag is context tag number 3 */
2652                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2653                         if (tag_is_context_specific(tag_info) && (tag_no == 3))
2654                                 offset = fUnsignedTag (tvb,tree,offset,"Priority: ");
2655                 }
2656         }
2657         return offset;
2658 }
2659
2660 static guint
2661 fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2662 {
2663         guint lastoffset = 0;
2664
2665         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2666                 lastoffset = offset;
2667
2668                 switch (fTagNo(tvb,offset)) {
2669                 case 0: /* ProcessId */
2670                         offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
2671                         break;
2672                 case 1: /* monitored ObjectId */
2673                         offset = fObjectIdentifier (tvb, tree, offset);
2674                         break;
2675                 case 2: /* issueConfirmedNotifications */
2676                         offset = fBooleanTag (tvb, tree, offset, "issue Confirmed Notifications: ");
2677                         break;
2678                 case 3: /* life time */
2679                         offset = fTimeSpan (tvb,tree,offset,"life time");
2680                         break;
2681                 case 4: /* monitoredPropertyIdentifier */
2682                         offset = fBACnetPropertyReference (tvb, tree, offset, 0);
2683                         break;
2684                 case 5: /* covIncrement */
2685                         offset = fRealTag (tvb, tree, offset, "COV Increment: ");
2686                         break;
2687                 default:
2688                         return offset;
2689                         break;
2690                 }
2691         }
2692         return offset;
2693 }
2694
2695 static guint
2696 fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2697 {
2698         return fSubscribeCOVPropertyRequest(tvb, tree, offset);
2699 }
2700
2701 static guint
2702 fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset)
2703 {
2704         guint lastoffset = 0;
2705
2706         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2707                 lastoffset = offset;
2708
2709                 switch (fTagNo(tvb, offset)) {
2710                 case 0: /* deviceInstanceLowLimit */
2711                         offset = fUnsignedTag (tvb, tree, offset, "device Instance Low Limit: ");
2712                         break;
2713                 case 1: /* deviceInstanceHighLimit */
2714                         offset = fUnsignedTag (tvb, tree, offset, "device Instance High Limit: ");
2715                         break;
2716                 case 2: /* BACnetObjectId */
2717                         offset = fObjectIdentifier (tvb, tree, offset);
2718                         break;
2719                 case 3: /* messageText */
2720                         offset = fCharacterString (tvb,tree,offset, "Object Name: ");
2721                         break;
2722                 default:
2723                         return offset;
2724                 }
2725         }
2726         return offset;
2727 }
2728
2729
2730 static guint
2731 fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset)
2732 {
2733         guint lastoffset = 0;
2734         guint8 tag_no, tag_info;
2735         guint32 lvt;
2736
2737         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2738         if (tag_is_opening(tag_info) && tag_no == 0)
2739         {
2740                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); /* opening context tag 0 */
2741                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2742                         lastoffset = offset;
2743                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2744                         if (tag_is_closing(tag_info)) {
2745                                 /* should be closing context tag 0 */
2746                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2747                                 return offset;
2748                         }
2749
2750                         offset = fTimeValue (tvb, subtree, offset);
2751                 }
2752         }
2753         else if (tag_no == 0 && lvt == 0)
2754         {
2755                 /* not sure null (empty array element) is legal */
2756                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2757         }
2758         return offset;
2759 }
2760
2761 static guint
2762 fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset)
2763 {
2764         guint lastoffset = 0;
2765         guint8 tag_no, tag_info;
2766         guint32 lvt;
2767         guint i=1;
2768         proto_tree *subtree = tree;
2769         proto_item *tt;
2770
2771         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2772                 lastoffset = offset;
2773                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2774                 if (tag_is_closing(tag_info)) {
2775                         return offset; /* outer encoding will print out closing tag */
2776                 }
2777                 tt = proto_tree_add_text(tree, tvb, offset, 0, val_to_str(i++, days, "day of week (%d) not found"));
2778                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2779                 offset = fDailySchedule (tvb,subtree,offset);
2780         }
2781         return offset;
2782 }
2783
2784
2785 static guint
2786 fUTCTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
2787 {
2788         if (tvb_length_remaining(tvb, offset) <= 0)
2789                 return offset;
2790
2791         return fDateTime (tvb, tree, offset, "UTC-Time: ");
2792 }
2793
2794 static guint
2795 fTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
2796 {
2797         if (tvb_length_remaining(tvb, offset) <= 0)
2798                 return offset;
2799
2800         return fDateTime (tvb, tree, offset, NULL);
2801 }
2802
2803 static guint
2804 fDateRange  (tvbuff_t *tvb, proto_tree *tree, guint offset)
2805 {
2806         if (tvb_length_remaining(tvb, offset) <= 0)
2807                 return offset;
2808     offset = fDate (tvb,tree,offset,"Start Date: ");
2809         return fDate (tvb, tree, offset, "End Date: ");
2810 }
2811
2812 static guint
2813 fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2814 {
2815         guint lastoffset = 0;
2816
2817         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2818                 lastoffset = offset;
2819                 switch (fTagNo(tvb, offset)) {
2820
2821                 case 0: /* textMessageSourceDevice */
2822                         offset = fObjectIdentifier (tvb, tree, offset);
2823                         break;
2824                 case 1: /* messageClass */
2825                         switch (fTagNo(tvb, offset)) {
2826                         case 0: /* numeric */
2827                                 offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
2828                                 break;
2829                         case 1: /* character */
2830                                 offset = fCharacterString (tvb, tree, offset, "message Class: ");
2831                                 break;
2832                         }
2833                         break;
2834                 case 2: /* messagePriority */
2835                         offset = fEnumeratedTag (tvb, tree, offset, "message Priority: ",
2836                                 BACnetMessagePriority);
2837                         break;
2838                 case 3: /* message */
2839                         offset = fCharacterString (tvb, tree, offset, "message: ");
2840                         break;
2841                 default:
2842                         return offset;
2843                         break;
2844                 }
2845         }
2846         return offset;
2847 }
2848
2849 static guint
2850 fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2851 {
2852         return fConfirmedTextMessageRequest(tvb, tree, offset);
2853 }
2854
2855 static guint
2856 fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2857 {
2858         guint lastoffset = 0;
2859         guint8 tag_no, tag_info;
2860         guint32 lvt;
2861         proto_tree *subtree = tree;
2862         proto_item *tt;
2863
2864         /* exit loop if nothing happens inside */
2865         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {
2866                 lastoffset = offset;
2867                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2868                 if (tag_is_closing(tag_info)) {
2869                         if (tag_no == 2) /* Make sure it's the expected tag */
2870                         {
2871                                 offset += fTagHeaderTree (tvb, subtree, offset,
2872                                         &tag_no, &tag_info, &lvt);
2873                                 subtree = tree;
2874                                 continue;
2875                         }
2876                         else
2877                         {
2878                                 break; /* End loop if incorrect closing tag */
2879                         }
2880                 }
2881                 switch (tag_no) {
2882
2883                 case 0: /* vendorID */
2884                         offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
2885                         break;
2886                 case 1: /* serviceNumber */
2887                         offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
2888                         break;
2889                 case 2: /*serviceParameters */
2890                         if (tag_is_opening(tag_info)) {
2891                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
2892                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2893                                 propertyIdentifier = -1;
2894                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2895                                 break;
2896                         }
2897                         FAULT;
2898                         break;
2899                 default:
2900                         return offset;
2901                 }
2902         }
2903         return offset;
2904 }
2905
2906 static guint
2907 fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2908 {
2909         return fConfirmedPrivateTransferRequest(tvb, tree, offset);
2910 }
2911
2912 static guint
2913 fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset)
2914 {
2915         return fConfirmedPrivateTransferRequest(tvb, tree, offset);
2916 }
2917
2918 static guint
2919 fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2920 {
2921         guint lastoffset = 0;
2922         guint8 tag_no, tag_info;
2923         guint32 lvt;
2924         proto_tree *subtree = tree;
2925         proto_item *tt;
2926
2927         if (label != NULL) {
2928                 tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", label);
2929                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2930         }
2931
2932         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2933                 lastoffset = offset;
2934                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2935
2936                 switch (tag_no) {
2937                 case 0: /* subscriberProcessId */
2938                         offset = fUnsignedTag (tvb, subtree, offset, "requesting Process Id: ");
2939                         break;
2940                 case 1: /* requestingSource */
2941                         offset = fCharacterString (tvb, tree, offset, "requesting Source: ");
2942                         break;
2943                 case 2: /* request */
2944                         offset = fEnumeratedTagSplit (tvb, tree, offset,
2945                                 "request: ", BACnetLifeSafetyOperation, 64);
2946                         break;
2947                 case 3: /* objectId */
2948                         offset = fObjectIdentifier (tvb, subtree, offset);
2949                         break;
2950                 default:
2951                         return offset;
2952                         break;
2953                 }
2954         }
2955         return offset;
2956 }
2957
2958 static guint fBACnetPropertyStates(tvbuff_t *tvb, proto_tree *tree, guint offset)
2959 {
2960         switch (fTagNo(tvb, offset))
2961         {
2962         case 0:
2963                 offset = fBooleanTag (tvb, tree, offset, "boolean-value: ");
2964                 break;
2965         case 1:
2966                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2967                         "binary-value: ", BACnetBinaryPV, 2);
2968                 break;
2969         case 2:
2970                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2971                         "event-type: ", BACnetEventType, 12);
2972                 break;
2973         case 3:
2974                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2975                         "polarity: ", BACnetPolarity, 2);
2976                 break;
2977         case 4:
2978                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2979                         "program-change: ", BACnetProgramRequest, 5);
2980                 break;
2981         case 5:
2982                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2983                         "program-state: ", BACnetProgramState, 5);
2984                 break;
2985         case 6:
2986                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2987                         "reason-for-halt: ", BACnetProgramError, 5);
2988                 break;
2989         case 7:
2990                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2991                         "reliability: ", BACnetReliability, 10);
2992                 break;
2993         case 8:
2994                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2995                         "state: ", BACnetEventState, 64);
2996                 break;
2997         case 9:
2998                 offset = fEnumeratedTagSplit (tvb, tree, offset,
2999                         "system-status: ", BACnetDeviceStatus, 64);
3000                 break;
3001         case 10:
3002                 offset = fEnumeratedTagSplit (tvb, tree, offset,
3003                         "units: ", BACnetEngineeringUnits, 2);
3004                 break;
3005         case 11:
3006                 offset = fUnsignedTag(tvb, tree, offset, "unsigned-value: ");
3007                 break;
3008         case 12:
3009                 offset = fEnumeratedTagSplit (tvb, tree, offset,
3010                         "life-safety-mode: ", BACnetLifeSafetyMode, 64);
3011                 break;
3012         case 13:
3013                 offset = fEnumeratedTagSplit (tvb, tree, offset,
3014                         "life-safety-state: ", BACnetLifeSafetyState, 64);
3015                 break;
3016         default:
3017                 break;
3018         }
3019         return offset;
3020 }
3021
3022 static guint
3023 fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
3024 {
3025         guint lastoffset = offset;
3026         guint8 tag_no, tag_info;
3027         guint32 lvt;
3028         proto_tree *subtree = tree;
3029         proto_item *tt;
3030
3031         tt = proto_tree_add_text(subtree, tvb, offset, 0, "notification parameters");
3032         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
3033         /* Opeing tag for parameter choice */
3034         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3035
3036         switch (tag_no) {
3037         case 0: /* change-of-bitstring */
3038                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3039                 lastoffset = offset;
3040                         switch (fTagNo(tvb, offset)) {
3041                         case 0:
3042                                 offset = fBitStringTag (tvb, subtree, offset,
3043                                         "referenced-bitstring: ");
3044                                 break;
3045                         case 1:
3046                                 offset = fBitStringTagVS (tvb, subtree, offset,
3047                                         "status-flags: ", BACnetStatusFlags);
3048                                 break;
3049                         default:
3050                                 break;
3051                         }
3052                 }
3053                 break;
3054         case 1: /* change-of-state */
3055                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3056                 lastoffset = offset;
3057                         switch (fTagNo(tvb, offset)) {
3058                         case 0:
3059                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3060                                 offset = fBACnetPropertyStates(tvb, subtree, offset);
3061                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3062                         case 1:
3063                                 offset = fBitStringTagVS (tvb, subtree, offset,
3064                                         "status-flags: ", BACnetStatusFlags);
3065                         lastoffset = offset;
3066                                 break;
3067                         default:
3068                                 break;
3069                         }
3070                 }
3071                 break;
3072     case 2: /* change-of-value */
3073                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3074                 lastoffset = offset;
3075                         switch (fTagNo(tvb, offset)) {
3076                         case 0:
3077                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3078                                 switch (fTagNo(tvb, offset)) {
3079                                 case 0:
3080                                         offset = fBitStringTag (tvb, subtree, offset,
3081                                                 "changed-bits: ");
3082                                         break;
3083                                 case 1:
3084                                         offset = fRealTag (tvb, subtree, offset,
3085                                                 "changed-value: ");
3086                                         break;
3087                                 default:
3088                                         break;
3089                                 }
3090                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3091                                 break;
3092                         case 1:
3093                                 offset = fBitStringTagVS (tvb, subtree, offset,
3094                                         "status-flags: ", BACnetStatusFlags);
3095                                 break;
3096                         default:
3097                                 break;
3098                         }
3099                 }
3100                 break;
3101     case 3: /* command-failure */
3102                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3103                 lastoffset = offset;
3104                         switch (fTagNo(tvb, offset)) {
3105                         case 0: /* "command-value: " */
3106                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3107                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3108                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3109                                 break;
3110                         case 1:
3111                                 offset = fBitStringTagVS (tvb, subtree, offset,
3112                                         "status-flags: ", BACnetStatusFlags);
3113                         case 2: /* "feedback-value: " */
3114                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3115                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3116                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3117                         default:
3118                                 break;
3119                         }
3120                 }
3121                 break;
3122     case 4: /* floating-limit */
3123                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3124                 lastoffset = offset;
3125                         switch (fTagNo(tvb, offset)) {
3126                         case 0:
3127                                 offset = fRealTag (tvb, subtree, offset, "reference-value: ");
3128                                 break;
3129                         case 1:
3130                                 offset = fBitStringTagVS (tvb, subtree, offset,
3131                                         "status-flags: ", BACnetStatusFlags);
3132                                 break;
3133                         case 2:
3134                                 offset = fRealTag (tvb, subtree, offset, "setpoint-value: ");
3135                                 break;
3136                         case 3:
3137                                 offset = fRealTag (tvb, subtree, offset, "error-limit: ");
3138                         default:
3139                                 break;
3140                         }
3141                 }
3142                 break;
3143     case 5: /* out-of-range */
3144                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3145                 lastoffset = offset;
3146                         switch (fTagNo(tvb, offset)) {
3147                         case 0:
3148                                 offset = fRealTag (tvb, subtree, offset, "exceeding-value: ");
3149                                 break;
3150                         case 1:
3151                                 offset = fBitStringTagVS (tvb, subtree, offset,
3152                                         "status-flags: ", BACnetStatusFlags);
3153                                 break;
3154                         case 2:
3155                                 offset = fRealTag (tvb, subtree, offset, "deadband: ");
3156                                 break;
3157                         case 3:
3158                                 offset = fRealTag (tvb, subtree, offset, "exceeded-limit: ");
3159                         default:
3160                                 break;
3161                         }
3162                 }
3163             break;
3164         case 6:
3165                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3166                 lastoffset = offset;
3167                         offset =fBACnetPropertyValue (tvb,subtree,offset);
3168                 }
3169                 break;
3170         case 7: /* buffer-ready */
3171                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3172                 lastoffset = offset;
3173                         switch (fTagNo(tvb, offset)) {
3174                         case 0:
3175                                 offset = fObjectIdentifier (tvb, subtree, offset); /* buffer-device */
3176                                 break;
3177                         case 1:
3178                                 offset = fObjectIdentifier (tvb, subtree, offset); /* buffer-object */
3179                                 break;
3180                         case 2:
3181                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3182                                 offset = fDateTime (tvb, subtree, offset, "previous-notification: ");
3183                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3184                                 break;
3185                         case 3:
3186                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3187                                 offset = fDateTime (tvb, subtree, offset, "current-notification: ");
3188                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3189                         default:
3190                                 break;
3191                         }
3192                 }
3193                 break;
3194     case 8: /* change-of-life-safety */
3195                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3196                 lastoffset = offset;
3197                         switch (fTagNo(tvb, offset)) {
3198                         case 0:
3199                                 offset = fEnumeratedTagSplit (tvb, subtree, offset,
3200                                         "new-state: ", BACnetLifeSafetyState, 256);
3201                                 break;
3202                         case 1:
3203                                 offset = fEnumeratedTagSplit (tvb, subtree, offset,
3204                                         "new-mode: ", BACnetLifeSafetyState, 256);
3205                                 break;
3206                         case 2:
3207                                 offset = fBitStringTagVS (tvb, subtree, offset,
3208                                         "status-flags: ", BACnetStatusFlags);
3209                         case 3:
3210                                 offset = fEnumeratedTagSplit (tvb, subtree, offset,
3211                                         "operation-expected: ", BACnetLifeSafetyOperation, 64);
3212                         default:
3213                                 break;
3214                         }
3215                 }
3216             break;
3217         default:
3218                 break;
3219         }
3220         /* Closing tag for parameter choice */
3221         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3222
3223         return offset;
3224 }
3225
3226 #if 0
3227 static guint
3228 fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset)
3229 {
3230         guint lastoffset = 0;
3231
3232         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3233                 lastoffset = offset;
3234                 switch (fTagNo(tvb, offset)) {
3235                 case 0: /* change-of-bitstring */
3236                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3237                                 lastoffset = offset;
3238                                 switch (fTagNo(tvb, offset)) {
3239                                 case 0:
3240                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3241                                         break;
3242                                 case 1:
3243                                         offset = fBitStringTag (tvb, tree, offset, "bitmask: ");
3244                                         break;
3245                                 case 2: /* SEQUENCE OF BIT STRING */
3246                                         offset = fBitStringTagVS (tvb, tree, offset,
3247                                                 "bitstring value: ", BACnetEventTransitionBits);
3248                                         break;
3249                                 default:
3250                                         return offset;
3251                                 }
3252                         }
3253         break;
3254                 case 1: /* change-of-state */
3255                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3256                         lastoffset = offset;
3257                                 switch (fTagNo(tvb, offset)) {
3258                                 case 0:
3259                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3260                                         break;
3261                                 case 1: /* SEQUENCE OF BACnetPropertyStates */
3262                                         offset = fEnumeratedTagSplit (tvb, tree, offset,
3263                                                 "value: ", BACnetPropertyStates, 64);
3264                                         break;
3265                                 default:
3266                                         return offset;
3267                                 }
3268                         }
3269                         break;
3270         case 2: /* change-of-value */
3271                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3272                         lastoffset = offset;
3273                                 switch (fTagNo(tvb, offset)) {
3274                                 case 0:
3275                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3276                                         break;
3277                                 case 1: /* don't loop it, it's a CHOICE */
3278                                         switch (fTagNo(tvb, offset)) {
3279                                         case 0:
3280                                                 offset = fBitStringTag (tvb, tree, offset, "bitmask: ");
3281                                                 break;
3282                                         case 1:
3283                                                 offset = fRealTag (tvb, tree, offset,
3284                                                         "referenced Property Increment: ");
3285                                                 break;
3286                                         default:
3287                                                 return offset;
3288                                         }
3289                                 default:
3290                                         return offset;
3291                                 }
3292                         }
3293                 break;
3294         case 3: /* command-failure */
3295                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3296                         lastoffset = offset;
3297                                 switch (fTagNo(tvb, offset)) {
3298                                 case 0:
3299                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3300                                         break;
3301                                 case 1:
3302                                         offset = fDeviceObjectPropertyReference (tvb,tree,offset);
3303                                 default:
3304                                         return offset;
3305                                 }
3306                         }
3307         break;
3308         case 4: /* floating-limit */
3309                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3310                         lastoffset = offset;
3311                                 switch (fTagNo(tvb, offset)) {
3312                                 case 0:
3313                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3314                                         break;
3315                                 case 1:
3316                                         offset = fDeviceObjectPropertyReference (tvb,tree,offset);
3317                                         break;
3318                                 case 2:
3319                                         offset = fRealTag (tvb, tree, offset, "low diff limit: ");
3320                                         break;
3321                                 case 3:
3322                                         offset = fRealTag (tvb, tree, offset, "high diff limit: ");
3323                                         break;
3324                                 case 4:
3325                                         offset = fRealTag (tvb, tree, offset, "deadband: ");
3326                                         break;
3327                                 default:
3328                                         return offset;
3329                                 }
3330                         }
3331                         break;
3332                 case 5: /* out-of-range */
3333                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3334                                 lastoffset = offset;
3335                                 switch (fTagNo(tvb, offset)) {
3336                                 case 0:
3337                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3338                                         break;
3339                                 case 1:
3340                                         offset = fRealTag (tvb, tree, offset, "low limit: ");
3341                                         break;
3342                                 case 2:
3343                                         offset = fRealTag (tvb, tree, offset, "high limit: ");
3344                                         break;
3345                                 case 3:
3346                                         offset = fRealTag (tvb, tree, offset, "deadband: ");
3347                                         break;
3348                                 default:
3349                                         return offset;
3350                                 }
3351                         }
3352         break;
3353                 case 6:
3354                         offset = fBACnetPropertyValue (tvb,tree,offset);
3355                         break;
3356                 case 7: /* buffer-ready */
3357                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3358                                 lastoffset = offset;
3359                                 switch (fTagNo(tvb, offset)) {
3360                                 case 0:
3361                                         offset = fUnsignedTag (tvb,tree,offset,"notification threshold");
3362                                         break;
3363                                 case 1:
3364                                         offset = fUnsignedTag (tvb,tree,offset,
3365                                                 "previous notification count: ");
3366                                         break;
3367                                 default:
3368                                         return offset;
3369                                 }
3370                         }
3371         break;
3372                 case 8: /* change-of-life-safety */
3373                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3374                                 lastoffset = offset;
3375                                 switch (fTagNo(tvb, offset)) {
3376                                 case 0:
3377                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3378                                         break;
3379                                 case 1:
3380                                         offset = fEnumeratedTagSplit (tvb, tree, offset,
3381                                                 "life safety alarm value: ", BACnetLifeSafetyState, 256);
3382                                         break;
3383                                 case 2:
3384                                         offset = fEnumeratedTagSplit (tvb, tree, offset,
3385                                                 "alarm value: ", BACnetLifeSafetyState, 256);
3386                                         break;
3387                                 case 3:
3388                                         offset = fDeviceObjectPropertyReference (tvb, tree, offset);
3389                                         break;
3390                                 default:
3391                                         return offset;
3392                                 }
3393                         }
3394                         break;
3395                 default:
3396                         return offset;
3397                 }
3398         }
3399         return offset;
3400 }
3401
3402 static guint
3403 fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset)
3404 {
3405         guint lastoffset = 0;
3406         guint8 tag_no, tag_info;
3407         guint32 lvt;
3408
3409         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3410                 lastoffset = offset;
3411                 switch (fTagNo(tvb, offset)) {
3412                 case 0: /* timestamp */
3413                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3414                         offset = fDateTime (tvb,tree,offset,NULL);
3415                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3416                         break;
3417                 case 1: /* logDatum: don't loop, it's a CHOICE */
3418                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3419                         switch (fTagNo(tvb, offset)) {
3420                         case 0: /* logStatus */
3421                                 offset = fEnumeratedTag (tvb, tree, offset,
3422                                         "log status: ", BACnetLogStatus);
3423                                 break;
3424                         case 1:
3425                                 offset = fBooleanTag (tvb, tree, offset, "boolean-value: ");
3426                                 break;
3427                         case 2:
3428                                 offset = fRealTag (tvb, tree, offset, "real value: ");
3429                                 break;
3430                         case 3:
3431                                 offset = fUnsignedTag (tvb, tree, offset, "enum value: ");
3432                                 break;
3433                         case 4:
3434                                 offset = fUnsignedTag (tvb, tree, offset, "unsigned value: ");
3435                                 break;
3436                         case 5:
3437                                 offset = fSignedTag (tvb, tree, offset, "signed value: ");
3438                                 break;
3439                         case 6:
3440                                 offset = fBitStringTag (tvb, tree, offset, "bitstring value: ");
3441                                 break;
3442                         case 7:
3443                                 offset = fNullTag(tvb, tree, offset, "null value: ");
3444                                 break;
3445                         case 8:
3446                                 offset = fError (tvb,tree,offset);
3447                                 break;
3448                         case 9:
3449                                 offset = fRealTag (tvb, tree, offset, "time change: ");
3450                                 break;
3451                         case 10:        /* any Value */
3452                                 offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3453                                 offset = fAbstractSyntaxNType (tvb, tree, offset);
3454                                 offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3455                                 break;
3456                         default:
3457                                 return offset;
3458                         }
3459                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3460         break;
3461                 case 2:
3462                         offset = fEnumeratedTag (tvb, tree, offset,
3463                                 "status Flags: ", BACnetStatusFlags);
3464                         break;
3465                 default:
3466                         return offset;
3467                 }
3468         }
3469         return offset;
3470 }
3471 #endif
3472
3473 static guint
3474 fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3475 {
3476         guint lastoffset = 0;
3477         guint8 tag_no, tag_info;
3478         guint32 lvt;
3479
3480         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3481                 lastoffset = offset;
3482
3483                 switch (fTagNo(tvb,offset)) {
3484                 case 0: /* ProcessId */
3485                         offset = fProcessId (tvb,tree,offset);
3486                         break;
3487                 case 1: /* initiating ObjectId */
3488                         offset = fObjectIdentifier (tvb, tree, offset);
3489                         break;
3490                 case 2: /* event ObjectId */
3491                         offset = fObjectIdentifier (tvb, tree, offset);
3492                         break;
3493                 case 3: /* time stamp */
3494                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3495                         offset = fTimeStamp (tvb, tree, offset);
3496                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3497                         break;
3498                 case 4: /* notificationClass */
3499                         offset = fUnsignedTag (tvb, tree, offset, "Notification Class: ");
3500                         break;
3501                 case 5: /* Priority */
3502                         offset = fUnsignedTag (tvb, tree, offset, "Priority: ");
3503                         break;
3504                 case 6: /* EventType */
3505                         offset = fEnumeratedTagSplit (tvb, tree, offset,
3506                                 "Event Type: ", BACnetEventType, 64);
3507                         break;
3508                 case 7: /* messageText */
3509                         offset = fCharacterString (tvb, tree, offset, "message Text: ");
3510                         break;
3511                 case 8: /* NotifyType */
3512                         offset = fEnumeratedTag (tvb, tree, offset,
3513                                 "Notify Type: ", BACnetNotifyType);
3514                         break;
3515                 case 9: /* ackRequired */
3516                         offset = fBooleanTag (tvb, tree, offset, "ack Required: ");
3517                         break;
3518                 case 10: /* fromState */
3519                         offset = fEnumeratedTagSplit (tvb, tree, offset,
3520                                 "from State: ", BACnetEventState, 64);
3521                         break;
3522                 case 11: /* toState */
3523                         offset = fEnumeratedTagSplit (tvb, tree, offset,
3524                                 "to State: ", BACnetEventState, 64);
3525                         break;
3526                 case 12: /* NotificationParameters */
3527                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3528                         offset = fNotificationParameters (tvb, tree, offset);
3529                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3530                         break;
3531                 default:
3532                         break;
3533                 }
3534         }
3535         return offset;
3536 }
3537
3538 static guint
3539 fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3540 {
3541         return fConfirmedEventNotificationRequest (tvb, tree, offset);
3542 }
3543
3544 static guint
3545 fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3546 {
3547         guint lastoffset = 0;
3548         guint8 tag_no, tag_info;
3549         guint32 lvt;
3550         proto_tree *subtree = tree;
3551         proto_item *tt;
3552
3553         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3554                 lastoffset = offset;
3555                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
3556                 if (tag_is_closing(tag_info)) {
3557                         offset += fTagHeaderTree (tvb, subtree, offset,
3558                                 &tag_no, &tag_info, &lvt);
3559                         lastoffset = offset;
3560                         subtree = tree;
3561                         continue;
3562                 }
3563
3564                 switch (tag_no) {
3565                 case 0: /* ProcessId */
3566                         offset = fProcessId (tvb,tree,offset);
3567                         break;
3568                 case 1: /* initiating DeviceId */
3569                         offset = fObjectIdentifier (tvb, subtree, offset);
3570                         break;
3571                 case 2: /* monitored ObjectId */
3572                         offset = fObjectIdentifier (tvb, subtree, offset);
3573                         break;
3574                 case 3: /* time remaining */
3575                         offset = fTimeSpan (tvb, tree, offset, "Time remaining");
3576                         break;
3577                 case 4: /* List of Values */
3578                         if (tag_is_opening(tag_info)) {
3579                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
3580                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
3581                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3582                                 offset = fBACnetPropertyValue (tvb, subtree, offset);
3583                                 break;
3584                         }
3585                         FAULT;
3586                         break;
3587                 default:
3588                         return offset;
3589                         break;
3590                 }
3591         }
3592         return offset;
3593 }
3594
3595 static guint
3596 fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3597 {
3598         return fConfirmedCOVNotificationRequest (tvb, tree, offset);
3599 }
3600
3601 static guint
3602 fAcknowledgeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3603 {
3604         guint lastoffset = 0;
3605         guint8 tag_no = 0, tag_info = 0;
3606         guint32 lvt = 0;
3607
3608         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3609                 lastoffset = offset;
3610                 switch (fTagNo(tvb, offset)) {
3611                 case 0: /* acknowledgingProcessId */
3612                         offset = fUnsignedTag (tvb, tree, offset, "acknowledging Process Id: ");
3613                         break;
3614                 case 1: /* eventObjectId */
3615                         offset = fObjectIdentifier (tvb, tree, offset);
3616                         break;
3617                 case 2: /* eventStateAcknowledged */
3618                         offset = fEnumeratedTagSplit (tvb, tree, offset,
3619                                 "event State Acknowledged: ", BACnetEventState, 64);
3620                         break;
3621                 case 3: /* timeStamp */
3622                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
3623                         offset = fTimeStamp(tvb, tree, offset);
3624                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
3625                         break;
3626                 case 4: /* acknowledgementSource */
3627                         offset = fCharacterString (tvb, tree, offset, "acknowledgement Source: ");
3628                         break;
3629                 case 5: /* timeOfAcknowledgement */
3630                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
3631                         offset = fTimeStamp(tvb, tree, offset);
3632                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
3633                         break;
3634                 default:
3635                         return offset;
3636                         break;
3637                 }
3638         }
3639         return offset;
3640 }
3641
3642 static guint
3643 fGetAlarmSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3644 {
3645         guint lastoffset = 0;
3646
3647         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3648                 lastoffset = offset;
3649                 offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: ");
3650                 offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset,
3651                         "alarm State: ", BACnetEventState, 64);
3652                 offset = fApplicationTypesEnumerated (tvb, tree, offset,
3653                         "acknowledged Transitions: ", BACnetEventTransitionBits);
3654         }
3655         return  offset;
3656 }
3657
3658 static guint
3659 fGetEnrollmentSummaryRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3660 {
3661         guint lastoffset = 0;
3662         guint8 tag_no, tag_info;
3663         guint32 lvt;
3664
3665         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3666                 lastoffset = offset;
3667                 switch (fTagNo(tvb, offset)) {
3668                 case 0: /* acknowledgmentFilter */
3669                         offset = fEnumeratedTag (tvb, tree, offset,
3670                                 "acknowledgment Filter: ", BACnetAcknowledgementFilter);
3671                         break;
3672                 case 1: /* eventObjectId - OPTIONAL */
3673                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3674                         offset = fRecipientProcess (tvb, tree, offset);
3675                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3676                         break;
3677                 case 2: /* eventStateFilter */
3678                         offset = fEnumeratedTag (tvb, tree, offset,
3679                                 "event State Filter: ", BACnetEventStateFilter);
3680                         break;
3681                 case 3: /* eventTypeFilter - OPTIONAL */
3682                         offset = fEnumeratedTag (tvb, tree, offset,
3683                                 "event Type Filter: ", BACnetEventType);
3684                         break;
3685                 case 4: /* priorityFilter */
3686                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3687                         offset = fUnsignedTag (tvb, tree, offset, "min Priority: ");
3688                         offset = fUnsignedTag (tvb, tree, offset, "max Priority: ");
3689                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3690                         break;
3691                 case 5: /* notificationClassFilter - OPTIONAL */
3692                         offset = fUnsignedTag (tvb, tree, offset, "notification Class Filter: ");
3693                         break;
3694                 default:
3695                         return offset;
3696                         break;
3697                 }
3698         }
3699         return offset;
3700 }
3701
3702 static guint
3703 fGetEnrollmentSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3704 {
3705         guint lastoffset = 0;
3706
3707         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3708                 lastoffset = offset;
3709                 offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: ");
3710                 offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, 
3711                         "event Type: ", BACnetEventType, 64);
3712                 offset = fApplicationTypesEnumerated (tvb, tree, offset, 
3713                         "event State: ", BACnetEventState);
3714                 offset = fApplicationTypes (tvb, tree, offset, "Priority: ");
3715                 offset = fApplicationTypes (tvb, tree, offset, "Notification Class: ");
3716         }
3717
3718         return  offset;
3719 }
3720
3721 static guint
3722 fGetEventInformationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3723 {
3724         if (tvb_length_remaining(tvb, offset) > 0) {
3725                 if (fTagNo(tvb, offset) == 0) {
3726                         offset = fObjectIdentifier (tvb, tree, offset);
3727                 }
3728         }
3729         return offset;
3730 }
3731
3732 static guint
3733 flistOfEventSummaries (tvbuff_t *tvb, proto_tree *tree, guint offset)
3734 {
3735         guint lastoffset = 0;
3736         guint8 tag_no, tag_info;
3737         guint32 lvt;
3738
3739         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3740                 lastoffset = offset;
3741                 switch (fTagNo(tvb, offset)) {
3742                 case 0: /* ObjectId */
3743                         offset = fObjectIdentifier (tvb, tree, offset);
3744                         break;
3745                 case 1: /* eventState */
3746                         offset = fEnumeratedTag (tvb, tree, offset,
3747                                 "event State: ", BACnetEventStateFilter);
3748                         break;
3749                 case 2: /* acknowledgedTransitions */
3750                         offset = fEnumeratedTag (tvb, tree, offset,
3751                                 "acknowledged Transitions: ", BACnetEventTransitionBits);
3752                         break;
3753                 case 3: /* eventTimeStamps */
3754                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3755                         offset = fTimeStamp (tvb, tree, offset);
3756                         offset = fTimeStamp (tvb, tree, offset);
3757                         offset = fTimeStamp (tvb, tree, offset);
3758                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3759                         break;
3760                 case 4: /* notifyType */
3761                         offset = fEnumeratedTag (tvb, tree, offset,
3762                                 "Notify Type: ", BACnetNotifyType);
3763                         break;
3764                 case 5: /* eventEnable */
3765                         offset = fEnumeratedTag (tvb, tree, offset,
3766                                 "event Enable: ", BACnetEventTransitionBits);
3767                         break;
3768                 case 6: /* eventPriorities */
3769                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3770                         offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
3771                         offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
3772                         offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
3773                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3774                         lastoffset = offset;
3775                         break;
3776                 default:
3777                         return offset;
3778                         break;
3779                 }
3780         }
3781         return offset;
3782 }
3783
3784 static guint
3785 fGetEventInformationACK (tvbuff_t *tvb, proto_tree *tree, guint offset)
3786 {
3787         guint lastoffset = 0;
3788         guint8 tag_no, tag_info;
3789         guint32 lvt;
3790
3791         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3792                 lastoffset = offset;
3793                 switch (fTagNo(tvb, offset)) {
3794                 case 0: /* listOfEventSummaries */
3795                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3796                         offset = flistOfEventSummaries (tvb, tree, offset);
3797                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3798                         break;
3799                 case 1: /* moreEvents */
3800                         offset = fBooleanTag (tvb, tree, offset, "more Events: ");
3801                         break;
3802                 default:
3803                         return offset;
3804                         break;
3805                 }
3806         }
3807         return offset;
3808 }
3809
3810 static guint
3811 fAddListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3812 {
3813         guint lastoffset = 0;
3814         guint8 tag_no, tag_info;
3815         guint32 lvt;
3816         proto_tree *subtree = tree;
3817         proto_item *tt;
3818
3819         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3820                 lastoffset = offset;
3821                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
3822                 if (tag_is_closing(tag_info)) {
3823                         offset += fTagHeaderTree (tvb, subtree, offset,
3824                                 &tag_no, &tag_info, &lvt);
3825                         subtree = tree;
3826                         continue;
3827                 }
3828
3829                 switch (tag_no) {
3830                 case 0: /* ObjectId */
3831                         offset = fBACnetObjectPropertyReference (tvb, subtree, offset);
3832                         break;
3833                 case 3: /* listOfElements */
3834                         if (tag_is_opening(tag_info)) {
3835                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfElements");
3836                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
3837                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3838                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3839                                 break;
3840                         }
3841                         FAULT;
3842                         break;
3843                 default:
3844                         return offset;
3845                         break;
3846                 }
3847         }
3848         return offset;
3849 }
3850
3851 static guint
3852 fDeleteObjectRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3853 {
3854         return fObjectIdentifier (tvb, tree, offset);
3855 }
3856
3857 static guint
3858 fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3859 {
3860         guint lastoffset = 0;
3861
3862         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3863                 lastoffset = offset;
3864
3865                 switch (fTagNo(tvb, offset)) {
3866                 case 0: /* timeDuration */
3867                         offset = fUnsignedTag (tvb,tree,offset,"time Duration: ");
3868                         break;
3869                 case 1: /* enable-disable */
3870                         offset = fEnumeratedTag (tvb, tree, offset, "enable-disable: ",
3871                                 BACnetEnableDisable);
3872                         break;
3873                 case 2: /* password - OPTIONAL */
3874                         offset = fCharacterString (tvb, tree, offset, "Password: ");
3875                         break;
3876                 default:
3877                         return offset;
3878                         break;
3879                 }
3880         }
3881         return offset;
3882 }
3883
3884 static guint
3885 fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3886 {
3887         guint lastoffset = 0;
3888
3889         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3890                 lastoffset = offset;
3891
3892                 switch (fTagNo(tvb, offset)) {
3893                 case 0: /* reinitializedStateOfDevice */
3894                         offset = fEnumeratedTag (tvb, tree, offset,
3895                                 "reinitialized State Of Device: ",
3896                                 BACnetReinitializedStateOfDevice);
3897                         break;
3898                 case 1: /* password - OPTIONAL */
3899                         offset = fCharacterString (tvb, tree, offset, "Password: ");
3900                         break;
3901                 default:
3902                         return offset;
3903                         break;
3904                 }
3905         }
3906         return offset;
3907 }
3908
3909 static guint
3910 fVtOpenRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3911 {
3912         offset = fApplicationTypesEnumerated (tvb, tree, offset,
3913                 "vtClass: ", BACnetVTClass);
3914         return fApplicationTypes (tvb,tree,offset,"local VT Session ID: ");
3915 }
3916
3917 static guint
3918 fVtOpenAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3919 {
3920         return fApplicationTypes (tvb,tree,offset,"remote VT Session ID: ");
3921 }
3922
3923 static guint
3924 fVtCloseRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3925 {
3926         guint lastoffset = 0;
3927
3928         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3929                 lastoffset = offset;
3930                 offset= fApplicationTypes (tvb,tree,offset,"remote VT Session ID: ");
3931         }
3932         return offset;
3933 }
3934
3935 static guint
3936 fVtDataRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3937 {
3938         offset= fApplicationTypes (tvb,tree,offset,"VT Session ID: ");
3939         offset = fApplicationTypes (tvb, tree, offset, "VT New Data: ");
3940         return fApplicationTypes (tvb,tree,offset,"VT Data Flag: ");;
3941 }
3942
3943 static guint
3944 fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3945 {
3946         guint lastoffset = 0;
3947
3948         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3949                 lastoffset = offset;
3950
3951                 switch (fTagNo(tvb,offset)) {
3952                 case 0: /* BOOLEAN */
3953                         offset = fBooleanTag (tvb, tree, offset, "all New Data Accepted: ");
3954                         break;
3955                 case 1: /* Unsigned OPTIONAL */
3956                         offset = fUnsignedTag (tvb, tree, offset, "accepted Octet Count: ");
3957                         break;
3958                 default:
3959                         return offset;
3960                 }
3961         }
3962         return offset;
3963 }
3964
3965 static guint
3966 fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3967 {
3968         guint lastoffset = 0;
3969
3970         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3971                 lastoffset = offset;
3972
3973                 switch (fTagNo(tvb,offset)) {
3974                 case 0: /* Unsigned32 */
3975                         offset = fUnsignedTag (tvb, tree, offset, "pseudo Random Number: ");
3976                         break;
3977                 case 1: /* expected Invoke ID Unsigned8 OPTIONAL */
3978                         proto_tree_add_item(tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
3979                         break;
3980                 case 2: /* Chararacter String OPTIONAL */
3981                         offset = fCharacterString (tvb, tree, offset, "operator Name: ");
3982                         break;
3983                 case 3: /* Chararacter String OPTIONAL */
3984                         offset = fCharacterString (tvb, tree, offset, "operator Password: ");
3985                         break;
3986                 case 4: /* Boolean OPTIONAL */
3987                         offset = fBooleanTag (tvb, tree, offset, "start Encyphered Session: ");
3988                         break;
3989                 default:
3990                         return offset;
3991                 }
3992         }
3993         return offset;
3994 }
3995
3996 static guint
3997 fAuthenticateAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3998 {
3999         return fApplicationTypes (tvb, tree, offset, "modified Random Number: ");
4000 }
4001
4002 static guint
4003 fRequestKeyRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
4004 {
4005         offset = fObjectIdentifier (tvb, tree, offset); /* Requesting Device Identifier */
4006         offset = fAddress (tvb, tree, offset);
4007         offset = fObjectIdentifier (tvb, tree, offset); /* Remote Device Identifier */
4008         return fAddress (tvb, tree, offset);
4009 }
4010
4011 static guint
4012 fRemoveListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4013 {
4014         /* Same as AddListElement request after service choice */
4015         return fAddListElementRequest(tvb, tree, offset);
4016 }
4017
4018 static guint
4019 fReadPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4020 {
4021         return fBACnetObjectPropertyReference(tvb, tree, offset);
4022 }
4023
4024 static guint
4025 fReadPropertyAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4026 {
4027         guint lastoffset = 0;
4028         guint8 tag_no, tag_info;
4029         guint32 lvt;
4030         proto_tree *subtree = tree;
4031     proto_item *tt;
4032
4033         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4034                 lastoffset = offset;
4035                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4036                 if (tag_is_closing(tag_info)) {
4037                         offset += fTagHeaderTree (tvb, subtree, offset,
4038                                 &tag_no, &tag_info, &lvt);
4039                         subtree = tree;
4040                         continue;
4041                 }
4042                 switch (tag_no) {
4043                 case 0: /* objectIdentifier */
4044                         offset = fObjectIdentifier (tvb, subtree, offset);
4045                         break;
4046                 case 1: /* propertyIdentifier */
4047                         offset = fPropertyIdentifier (tvb, subtree, offset);
4048                         break;
4049                 case 2: /* propertyArrayIndex */
4050                         offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
4051                         break;
4052                 case 3: /* propertyValue */
4053                         if (tag_is_opening(tag_info)) {
4054                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
4055                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4056                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4057                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
4058                                 break;
4059                         }
4060                         FAULT;
4061                         break;
4062                 default:
4063                         break;
4064                 }
4065         }
4066         return offset;
4067 }
4068
4069 static guint
4070 fWritePropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4071 {
4072         guint lastoffset = 0;
4073         guint8 tag_no, tag_info;
4074         guint32 lvt;
4075         proto_tree *subtree = tree;
4076     proto_item *tt;
4077
4078         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4079                 lastoffset = offset;
4080                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4081                 if (tag_is_closing(tag_info)) {
4082                         offset += fTagHeaderTree (tvb, subtree, offset,
4083                                 &tag_no, &tag_info, &lvt);
4084                         subtree = tree;
4085                         continue;
4086                 }
4087
4088                 switch (tag_no) {
4089                 case 0: /* objectIdentifier */
4090                         offset = fObjectIdentifier (tvb, subtree, offset);
4091                         break;
4092                 case 1: /* propertyIdentifier */
4093                         offset = fPropertyIdentifier (tvb, subtree, offset);
4094                         break;
4095                 case 2: /* propertyArrayIndex */
4096                         offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
4097                         break;
4098                 case 3: /* propertyValue */
4099                         if (tag_is_opening(tag_info)) {
4100                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
4101                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4102                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4103                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
4104                                 break;
4105                         }
4106                         FAULT;
4107                         break;
4108                 case 4: /* Priority (only used for write) */
4109                         offset = fUnsignedTag (tvb, subtree, offset, "Priority: ");
4110                         break;
4111                 default:
4112                         return offset;
4113                 }
4114         }
4115         return offset;
4116 }
4117
4118 static guint
4119 fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
4120 {
4121         guint lastoffset = 0;
4122         guint8 tag_no, tag_info;
4123         guint32 lvt;
4124
4125         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4126                 lastoffset = offset;
4127                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4128                 if (tag_is_closing(tag_info)) {
4129                         offset += fTagHeaderTree (tvb, subtree, offset,
4130                                 &tag_no, &tag_info, &lvt);
4131                         continue;
4132                 }
4133
4134                 switch (tag_no) {
4135                 case 0: /* objectIdentifier */
4136                         offset = fObjectIdentifier (tvb, subtree, offset);
4137                         break;
4138                 case 1: /* listOfPropertyValues */
4139                         if (tag_is_opening(tag_info)) {
4140                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4141                                 offset = fBACnetPropertyValue (tvb, subtree, offset);
4142                                 break;
4143                         }
4144                         FAULT;
4145                         break;
4146                 default:
4147                         return offset;
4148                 }
4149         }
4150         return offset;
4151 }
4152
4153 static guint
4154 fWritePropertyMultipleRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4155 {
4156         if (offset >= tvb_reported_length(tvb))
4157                 return offset;
4158
4159         return fWriteAccessSpecification (tvb, tree, offset);
4160 }
4161
4162 static guint
4163 fPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 tagoffset, guint8 list)
4164 {
4165         guint lastoffset = 0;
4166         guint8 tag_no, tag_info;
4167         guint32 lvt;
4168
4169         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4170                 lastoffset = offset;
4171                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4172                 if (tag_is_closing(tag_info)) { /* closing Tag, but not for me */
4173                         return offset;
4174                 }
4175                 switch (tag_no-tagoffset) {
4176                 case 0: /* PropertyIdentifier */
4177                         offset = fPropertyIdentifier (tvb, tree, offset);
4178                         break;
4179                 case 1: /* propertyArrayIndex */
4180                         offset = fUnsignedTag (tvb, tree, offset, "property Array Index: ");
4181                         if (list != 0) break; /* Continue decoding if this may be a list */
4182                 default:
4183                         lastoffset = offset; /* Set loop end condition */
4184                         break;
4185                 }
4186         }
4187         return offset;
4188 }
4189
4190 static guint
4191 fBACnetPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 list)
4192 {
4193         return fPropertyReference(tvb, tree, offset, 0, list);
4194 }
4195
4196 static guint
4197 fBACnetObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
4198 {
4199         guint lastoffset = 0;
4200
4201         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4202                 lastoffset = offset;
4203
4204                 switch (fTagNo(tvb,offset)) {
4205                 case 0: /* ObjectIdentifier */
4206                         offset = fObjectIdentifier (tvb, tree, offset);
4207                         break;
4208                 case 1: /* PropertyIdentifier and propertyArrayIndex */
4209                         offset = fPropertyReference (tvb, tree, offset, 1, 0);
4210                 default:
4211                         lastoffset = offset; /* Set loop end condition */
4212                         break;
4213                 }
4214         }
4215         return offset;
4216 }
4217
4218 #if 0
4219 static guint
4220 fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
4221 {
4222         guint lastoffset = 0;
4223         guint8 tag_no, tag_info;
4224         guint32 lvt;
4225         proto_tree* subtree = tree;
4226         proto_item* tt;
4227
4228         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4229                 lastoffset = offset;
4230                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4231                 if (tag_is_closing(tag_info)) {
4232                         offset += fTagHeaderTree (tvb, subtree, offset,
4233                                 &tag_no, &tag_info, &lvt);
4234                         continue;
4235                 }
4236                 switch (tag_no) {
4237                 case 0: /* ObjectIdentifier */
4238                         offset = fObjectIdentifier (tvb, subtree, offset);
4239                         break;
4240                 case 1: /* PropertyIdentifier */
4241                         offset = fPropertyIdentifier (tvb, subtree, offset);
4242                         break;
4243                 case 2: /* propertyArrayIndex */
4244                         offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
4245                         break;
4246                 case 3:  /* Value */
4247                         if (tag_is_opening(tag_info)) {
4248                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
4249                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4250                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4251                                 offset = fAbstractSyntaxNType   (tvb, subtree, offset);
4252                                 break;
4253                         }
4254                         FAULT;
4255                         break;
4256                 case 4:  /* Priority */
4257                         offset = fUnsignedTag (tvb, subtree, offset, "Priority: ");
4258                         break;
4259                 default:
4260                         break;
4261                 }
4262         }
4263         return offset;
4264 }
4265 #endif
4266
4267 #if 0
4268 static guint
4269 fDeviceObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
4270 {
4271         guint lastoffset = 0;
4272
4273         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4274                 lastoffset = offset;
4275
4276                 switch (fTagNo(tvb,offset)) {
4277                 case 0: /* ObjectIdentifier */
4278                         offset = fBACnetObjectPropertyReference (tvb, tree, offset);
4279                         break;
4280                 case 3: /* deviceIdentifier - OPTIONAL */
4281                         offset = fObjectIdentifier (tvb, tree, offset);
4282                         break;
4283                 default:
4284                         return offset;
4285                 }
4286         }
4287         return offset;
4288 }
4289 #endif
4290
4291 static guint
4292 fPriorityArray (tvbuff_t *tvb, proto_tree *tree, guint offset)
4293 {
4294         char i, ar[256];
4295
4296         if (offset >= tvb_reported_length(tvb))
4297                 return offset;
4298
4299         for (i = 1; i <= 16; i++) {
4300                 g_snprintf (ar, sizeof(ar), "%s[%d]: ",
4301                         val_to_split_str(87 , 512,
4302                                 BACnetPropertyIdentifier,
4303                                 ASHRAE_Reserved_Fmt,
4304                                 Vendor_Proprietary_Fmt),
4305                         i);
4306                 /* DMR Should be fAbstractNSyntax, but that's where we came from! */
4307                 offset = fApplicationTypes(tvb, tree, offset, ar);
4308         }
4309         return offset;
4310 }
4311
4312 static guint
4313 fDeviceObjectReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
4314 {
4315         guint lastoffset = 0;
4316
4317         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4318                 lastoffset = offset;
4319
4320                 switch (fTagNo(tvb,offset)) {
4321                 case 0: /* deviceIdentifier - OPTIONAL */
4322                         offset = fObjectIdentifier (tvb, tree, offset);
4323                         break;
4324                 case 1: /* ObjectIdentifier */
4325                         offset = fObjectIdentifier (tvb, tree, offset);
4326                         break;
4327                 default:
4328                         return offset;
4329                 }
4330         }
4331         return offset;
4332 }
4333
4334 static guint
4335 fSpecialEvent (tvbuff_t *tvb, proto_tree *subtree, guint offset)
4336 {
4337         guint8 tag_no, tag_info;
4338         guint32 lvt;
4339         guint lastoffset = 0;
4340
4341         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4342                 lastoffset = offset;
4343                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4344                 if (tag_is_closing(tag_info)) {
4345                         continue;
4346                 }
4347
4348                 switch (tag_no) {
4349                 case 0: /* calendaryEntry */
4350             if (tag_is_opening(tag_info))
4351             {
4352                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4353                         offset = fCalendaryEntry (tvb, subtree, offset);
4354                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4355             }
4356                         break;
4357                 case 1: /* calendarReference */
4358                         offset = fObjectIdentifier (tvb, subtree, offset);
4359                         break;
4360                 case 2: /* list of BACnetTimeValue */
4361                         if (tag_is_opening(tag_info)) {
4362                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4363                                 offset = fTimeValue (tvb, subtree, offset);
4364                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4365                                 break;
4366                         }
4367                         FAULT;
4368                         break;
4369                 case 3: /* eventPriority */
4370                         offset = fUnsignedTag (tvb, subtree, offset, "event priority: ");
4371                         break;
4372                 default:
4373                         return offset;
4374                 }
4375         }
4376         return offset;
4377 }
4378
4379 static guint
4380 fSelectionCriteria (tvbuff_t *tvb, proto_tree *tree, guint offset)
4381 {
4382         guint lastoffset = 0;
4383         guint8 tag_no, tag_info;
4384         guint32 lvt;
4385
4386         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4387                 lastoffset = offset;
4388                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4389                 if (tag_is_closing(tag_info)) {  /* stop when we hit outer closing tag */
4390                         continue;
4391                 }
4392                 
4393                 switch (fTagNo(tvb,offset)) {
4394                 case 0: /* propertyIdentifier */
4395                         offset = fPropertyIdentifier (tvb, tree, offset);
4396                         break;
4397                 case 1: /* propertyArrayIndex */
4398                         offset = fUnsignedTag (tvb, tree, offset, "property Array Index: ");
4399                         break;
4400                 case 2: /* relationSpecifier */
4401                         offset = fEnumeratedTag (tvb, tree, offset,
4402                                 "relation Specifier: ", BACnetRelationSpecifier);
4403                         break;
4404                 case 3: /* comparisonValue */
4405                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
4406                         offset = fAbstractSyntaxNType (tvb, tree, offset);
4407                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
4408                         break;
4409                 default:
4410                         return offset;
4411                 }
4412         }
4413         return offset;
4414 }
4415
4416 static guint
4417 fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset)
4418 {
4419         guint lastoffset = 0;
4420         guint8 tag_no, tag_info;
4421         guint32 lvt;
4422
4423         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4424                 lastoffset = offset;
4425                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4426                 if (tag_is_closing(tag_info)) {  /* stop when we hit outer closing tag */
4427                         continue;
4428                 }
4429
4430                 switch (tag_no) {
4431                 case 0: /* selectionLogic */
4432                         offset = fEnumeratedTag (tvb, subtree, offset,
4433                                 "selection Logic: ", BACnetSelectionLogic);
4434                         break;
4435                 case 1: /* listOfSelectionCriteria */
4436                         if (tag_is_opening(tag_info)) {
4437                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4438                                 offset = fSelectionCriteria (tvb, subtree, offset);
4439                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4440                                 break;
4441                         }
4442                         FAULT;
4443                         break;
4444                 default:
4445                         return offset;
4446                 }
4447         }
4448         return offset;
4449 }
4450
4451
4452 static guint
4453 fReadPropertyConditionalRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
4454 {
4455         guint lastoffset = 0;
4456         guint8 tag_no, tag_info;
4457         guint32 lvt;
4458
4459         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4460                 lastoffset = offset;
4461                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4462
4463                 if (tag_is_opening(tag_info) && tag_no < 2) {
4464                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4465                         switch (tag_no) {
4466                         case 0: /* objectSelectionCriteria */
4467                                 offset = fObjectSelectionCriteria (tvb, subtree, offset);
4468                                 break;
4469                         case 1: /* listOfPropertyReferences */
4470                                 offset = fBACnetPropertyReference (tvb, subtree, offset, 1);
4471                                 break;
4472                         default:
4473                                 return offset;
4474                         }
4475                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4476                 }
4477         }
4478         return offset;
4479 }
4480
4481 static guint
4482 fReadAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
4483 {
4484         guint lastoffset = 0;
4485         guint8 tag_no, tag_info;
4486         guint32 lvt;
4487
4488         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4489                 lastoffset = offset;
4490                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4491                 if (tag_is_closing(tag_info)) {
4492                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no,
4493                                 &tag_info, &lvt);
4494                         continue;
4495                 }
4496
4497                 switch (tag_no) {
4498                 case 0: /* objectIdentifier */
4499                         offset = fObjectIdentifier (tvb, subtree, offset);
4500                         break;
4501                 case 1: /* listOfPropertyReferences */
4502                         if (tag_is_opening(tag_info)) {
4503                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4504                                 offset = fBACnetPropertyReference (tvb, subtree, offset, 1);
4505                                 break;
4506                         }
4507                         FAULT;
4508                         break;
4509                 default:
4510                         return offset;
4511                 }
4512         }
4513         return offset;
4514 }
4515
4516 static guint
4517 fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset)
4518 {
4519         guint lastoffset = 0;
4520         guint8 tag_no;
4521         guint8 tag_info;
4522         guint32 lvt;
4523         proto_tree *subtree = tree;
4524         proto_item *tt;
4525
4526         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4527                 lastoffset = offset;
4528                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4529                 if (tag_is_closing(tag_info)) {
4530                         offset += fTagHeaderTree (tvb, subtree, offset,
4531                                 &tag_no, &tag_info, &lvt);
4532                         if (tag_no == 4 || tag_no == 5) subtree = tree; /* Value and error have extra subtree */
4533                         continue;
4534                 }
4535
4536                 switch (tag_no) {
4537                 case 0: /* objectSpecifier */
4538                         offset = fObjectIdentifier (tvb, subtree, offset);
4539                         break;
4540                 case 1: /* list of Results */
4541                         if (tag_is_opening(tag_info)) {
4542                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfResults");
4543                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4544                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4545                                 break;
4546                         }
4547                         FAULT;
4548                         break;
4549                 case 2: /* propertyIdentifier */
4550                         offset = fPropertyValue(tvb, subtree, offset, 2);
4551                         break;
4552                 case 5: /* propertyAccessError */
4553                         if (tag_is_opening(tag_info)) {
4554                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyAccessError");
4555                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4556                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4557                                 /* Error Code follows */
4558                                 offset = fError(tvb, subtree, offset);
4559                                 break;
4560                         }
4561                         FAULT;
4562                         break;
4563                 default:
4564                         return offset;
4565                 }
4566         }
4567         return offset;
4568 }
4569
4570
4571 static guint
4572 fReadPropertyConditionalAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4573 {
4574         /* listOfReadAccessResults */
4575         return fReadAccessResult (tvb, tree, offset);
4576 }
4577
4578
4579 static guint
4580 fCreateObjectRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
4581 {
4582         guint lastoffset = 0;
4583         guint8 tag_no, tag_info;
4584         guint32 lvt;
4585
4586         while ((tvb_length_remaining(tvb, offset) > 0) && (offset > lastoffset)) {  /* exit loop if nothing happens inside */
4587                 lastoffset = offset;
4588                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4589
4590                 if (tag_no < 2)
4591                 {
4592                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4593                         switch (tag_no) {
4594                         case 0: /* objectSpecifier */
4595                                 switch (fTagNo(tvb, offset)) { /* choice of objectType or objectIdentifier */
4596                                 case 0: /* objectType */
4597                                         offset = fEnumeratedTagSplit (tvb, subtree, offset, "Object Type: ", BACnetObjectType, 128);
4598                                         break;
4599                                 case 1: /* objectIdentifier */
4600                                         offset = fObjectIdentifier (tvb, subtree, offset);
4601                                         break;
4602                                 default:
4603                                         break;
4604                                 }
4605                                 break;
4606                         case 1: /* propertyValue */
4607                                 if (tag_is_opening(tag_info)) {
4608                                         offset = fBACnetPropertyValue (tvb, subtree, offset);
4609                                         break;
4610                                 }
4611                                 FAULT;
4612                                 break;
4613                         default:
4614                                 break;
4615                         }
4616                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4617                 }
4618         }
4619         return offset;
4620 }
4621
4622 static guint
4623 fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4624 {
4625         return fObjectIdentifier (tvb, tree, offset);
4626 }
4627
4628 static guint
4629 fReadRangeRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
4630 {
4631         guint8 tag_no, tag_info;
4632         guint32 lvt;
4633         proto_tree *subtree = tree;
4634         proto_item *tt;
4635
4636         offset = fBACnetObjectPropertyReference(tvb, subtree, offset);
4637
4638         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4639         /* optional range choice */
4640         if (tag_is_opening(tag_info)) {
4641                 tt = proto_tree_add_text(subtree, tvb, offset, 1, val_to_str(tag_no, BACnetReadRangeOptions, "unknown range option"));
4642                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4643                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4644                 switch (tag_no) {
4645                 case 3: /* range byPosition */
4646                 case 6: /* range bySequenceNumber, 2004 spec */
4647                         offset = fApplicationTypes (tvb, subtree, offset, "reference Index: ");
4648                         offset = fApplicationTypes (tvb, subtree, offset, "reference Count: ");
4649                         break;
4650                 case 4: /* range byTime - deprecated in 2004 */
4651                 case 7: /* 2004 spec */
4652                         offset = fDateTime(tvb, subtree, offset, "reference Date/Time: ");
4653                         offset = fApplicationTypes (tvb, subtree, offset, "reference Count: ");
4654                         break;
4655                 case 5: /* range timeRange - deprecated in 2004 */
4656                         offset = fDateTime(tvb, subtree, offset, "beginning Time: ");
4657                         offset = fDateTime(tvb, subtree, offset, "ending Time: ");
4658                         break;
4659                 default:
4660                         break;
4661                 }
4662                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4663         }
4664         return offset;
4665 }
4666
4667 static guint
4668 fReadRangeAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4669 {
4670         guint8 tag_no, tag_info;
4671         guint32 lvt;
4672         proto_tree *subtree = tree;
4673         proto_item *tt;
4674
4675         offset = fBACnetObjectPropertyReference(tvb, subtree, offset);
4676         
4677         /* resultFlags */
4678         offset = fEnumeratedTag (tvb, tree, offset, "result Flags: ", BACnetResultFlags);
4679         
4680         /* itemCount */
4681         offset = fUnsignedTag (tvb, subtree, offset, "item Count: ");
4682
4683         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4684         /* itemData */
4685         if (tag_is_opening(tag_info)) {
4686                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "itemData");
4687                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4688                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4689                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
4690                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4691         }
4692
4693         if (fTagNo(tvb, offset) == 6) { /* firstSequenceNumber - OPTIONAL */
4694                 offset = fUnsignedTag (tvb, subtree, offset, "first Sequence Number: ");
4695         }
4696
4697         return offset;
4698 }
4699
4700 static guint fAccessMethod(tvbuff_t *tvb, proto_tree *tree, guint offset)
4701 {
4702         guint lastoffset = 0;
4703         guint32 lvt;
4704         guint8 tag_no, tag_info;
4705         proto_item* tt;
4706         proto_tree* subtree = NULL;
4707
4708         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4709
4710         if (tag_is_opening(tag_info))
4711         {
4712                 tt = proto_tree_add_text(tree, tvb, offset, 1, val_to_str(tag_no, BACnetFileAccessOption, "invalid access method"));
4713                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4714                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4715                 offset = fApplicationTypes (tvb, subtree, offset, val_to_str(tag_no, BACnetFileStartOption, "invalid option"));
4716                 offset = fApplicationTypes (tvb, subtree, offset, val_to_str(tag_no, BACnetFileWriteInfo, "unknown option"));
4717
4718                 if (tag_no == 1)
4719                 {
4720                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset))
4721                         {  /* exit loop if nothing happens inside */
4722                                 lastoffset = offset;
4723                                 offset = fApplicationTypes (tvb, subtree, offset, "Record Data: ");
4724                         }
4725                 }
4726
4727                 if ((bacapp_flags & BACAPP_MORE_SEGMENTS) == 0)
4728                 {
4729                         /* More Flag is not set, so we can look for closing tag in this segment */
4730                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4731                         if (tag_is_closing(tag_info)) {
4732                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4733                         }
4734                 }
4735         }       
4736         return offset;
4737 }
4738
4739 static guint
4740 fAtomicReadFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4741 {
4742         guint8 tag_no, tag_info;
4743         guint32 lvt;
4744         proto_tree *subtree = tree;
4745         proto_item *tt;
4746
4747         offset = fObjectIdentifier (tvb, tree, offset);
4748
4749         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4750
4751         if (tag_is_opening(tag_info))
4752         {
4753                 tt = proto_tree_add_text(subtree, tvb, offset, 1, val_to_str(tag_no, BACnetFileAccessOption, "unknown access method"));
4754                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4755                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4756                 offset = fSignedTag (tvb, subtree, offset, val_to_str(tag_no, BACnetFileStartOption, "unknown option"));
4757                 offset = fUnsignedTag (tvb, subtree, offset, val_to_str(tag_no, BACnetFileRequestCount, "unknown option"));
4758                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4759         }
4760         return offset;
4761 }
4762
4763 static guint
4764 fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4765 {
4766
4767         offset = fObjectIdentifier (tvb, tree, offset); /* file Identifier */
4768     offset = fAccessMethod(tvb, tree, offset);
4769
4770         return offset;
4771 }
4772
4773 static guint
4774 fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4775 {
4776         guint tag_no = fTagNo(tvb, offset);
4777         return fSignedTag (tvb, tree, offset, val_to_str(tag_no, BACnetFileStartOption, "unknown option"));
4778 }
4779
4780 static guint
4781 fAtomicReadFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4782 {
4783         offset = fApplicationTypes (tvb, tree, offset, "End Of File: ");
4784     offset = fAccessMethod(tvb, tree, offset);
4785
4786     return offset;
4787 }
4788
4789 static guint
4790 fReadPropertyMultipleRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
4791 {
4792         return fReadAccessSpecification (tvb,subtree,offset);
4793 }
4794
4795 static guint
4796 fReadPropertyMultipleAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4797 {
4798         return fReadAccessResult (tvb,tree,offset);
4799 }
4800
4801 static guint
4802 fConfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
4803 {
4804         if (tvb_length_remaining(tvb,offset) <= 0)
4805                 return offset;
4806
4807         switch (service_choice) {
4808         case 0: /* acknowledgeAlarm */
4809                 offset = fAcknowledgeAlarmRequest (tvb, tree, offset);
4810                 break;
4811         case 1: /* confirmedCOVNotification */
4812                 offset = fConfirmedCOVNotificationRequest (tvb, tree, offset);
4813                 break;
4814         case 2: /* confirmedEventNotification */
4815                 offset = fConfirmedEventNotificationRequest (tvb, tree, offset);
4816                 break;
4817         case 3: /* confirmedGetAlarmSummary conveys no parameters */
4818                 break;
4819         case 4: /* getEnrollmentSummaryRequest */
4820                 offset = fGetEnrollmentSummaryRequest (tvb, tree, offset);
4821                 break;
4822         case 5: /* subscribeCOVRequest */
4823                 offset = fSubscribeCOVRequest(tvb, tree, offset);
4824                 break;
4825         case 6: /* atomicReadFile-Request */
4826                 offset = fAtomicReadFileRequest(tvb, tree, offset);
4827                 break;
4828         case 7: /* atomicWriteFile-Request */
4829                 offset = fAtomicWriteFileRequest(tvb, tree, offset);
4830                 break;
4831         case 8: /* AddListElement-Request */
4832                 offset = fAddListElementRequest(tvb, tree, offset);
4833                 break;
4834         case 9: /* removeListElement-Request */
4835                 offset = fRemoveListElementRequest(tvb, tree, offset);
4836                 break;
4837         case 10: /* createObjectRequest */
4838                 offset = fCreateObjectRequest(tvb, tree, offset);
4839                 break;
4840         case 11: /* deleteObject */
4841                 offset = fDeleteObjectRequest(tvb, tree, offset);
4842                 break;
4843         case 12:
4844                 offset = fReadPropertyRequest(tvb, tree, offset);
4845                 break;
4846         case 13:
4847                 offset = fReadPropertyConditionalRequest(tvb, tree, offset);
4848                 break;
4849         case 14:
4850                 offset = fReadPropertyMultipleRequest(tvb, tree, offset);
4851                 break;
4852         case 15:
4853                 offset = fWritePropertyRequest(tvb, tree, offset);
4854                 break;
4855         case 16:
4856                 offset = fWritePropertyMultipleRequest(tvb, tree, offset);
4857                 break;
4858         case 17:
4859                 offset = fDeviceCommunicationControlRequest(tvb, tree, offset);
4860                 break;
4861         case 18:
4862                 offset = fConfirmedPrivateTransferRequest(tvb, tree, offset);
4863                 break;
4864         case 19:
4865                 offset = fConfirmedTextMessageRequest(tvb, tree, offset);
4866                 break;
4867         case 20:
4868                 offset = fReinitializeDeviceRequest(tvb, tree, offset);
4869                 break;
4870         case 21:
4871                 offset = fVtOpenRequest(tvb, tree, offset);
4872                 break;
4873         case 22:
4874                 offset = fVtCloseRequest (tvb, tree, offset);
4875                 break;
4876         case 23:
4877                 offset = fVtDataRequest (tvb, tree, offset);
4878                 break;
4879         case 24:
4880                 offset = fAuthenticateRequest (tvb, tree, offset);
4881                 break;
4882         case 25:
4883                 offset = fRequestKeyRequest (tvb, tree, offset);
4884                 break;
4885         case 26:
4886                 offset = fReadRangeRequest (tvb, tree, offset);
4887                 break;
4888         case 27:
4889                 offset = fLifeSafetyOperationRequest(tvb, tree, offset, NULL);
4890                 break;
4891         case 28:
4892                 offset = fSubscribeCOVPropertyRequest(tvb, tree, offset);
4893                 break;
4894         case 29:
4895                 offset = fGetEventInformationRequest (tvb, tree, offset);
4896                 break;
4897         default:
4898                 return offset;
4899                 break;
4900         }
4901         return offset;
4902 }
4903
4904 static guint
4905 fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
4906 {
4907         if (tvb_length_remaining(tvb,offset) <= 0)
4908                 return offset;
4909
4910         switch (service_choice) {
4911         case 3: /* confirmedEventNotificationAck */
4912                 offset = fGetAlarmSummaryAck (tvb, tree, offset);
4913                 break;
4914         case 4: /* getEnrollmentSummaryAck */
4915                 offset = fGetEnrollmentSummaryAck (tvb, tree, offset);
4916                 break;
4917         case 6: /* atomicReadFile */
4918                 offset = fAtomicReadFileAck (tvb, tree, offset);
4919                 break;
4920         case 7: /* atomicReadFileAck */
4921                 offset = fAtomicWriteFileAck (tvb, tree, offset);
4922                 break;
4923         case 10: /* createObject */
4924                 offset = fCreateObjectAck (tvb, tree, offset);
4925                 break;
4926         case 12:
4927                 offset = fReadPropertyAck (tvb, tree, offset);
4928                 break;
4929         case 13:
4930                 offset = fReadPropertyConditionalAck (tvb, tree, offset);
4931                 break;
4932         case 14:
4933                 offset = fReadPropertyMultipleAck (tvb, tree, offset);
4934                 break;
4935         case 18:
4936                 offset = fConfirmedPrivateTransferAck(tvb, tree, offset);
4937                 break;
4938         case 21:
4939                 offset = fVtOpenAck (tvb, tree, offset);
4940                 break;
4941         case 23:
4942                 offset = fVtDataAck (tvb, tree, offset);
4943                 break;
4944         case 24:
4945                 offset = fAuthenticateAck (tvb, tree, offset);
4946                 break;
4947         case 26:
4948                 offset = fReadRangeAck (tvb, tree, offset);
4949                 break;
4950         case 29:
4951                 offset = fGetEventInformationACK (tvb, tree, offset);
4952                 break;
4953         default:
4954                 return offset;
4955         }
4956         return offset;
4957 }
4958
4959 static guint
4960 fIAmRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
4961 {
4962         /* BACnetObjectIdentifier */
4963         offset = fApplicationTypes (tvb, tree, offset, "BACnet Object Identifier: ");
4964
4965         /* MaxAPDULengthAccepted */
4966         offset = fApplicationTypes (tvb, tree, offset, "Maximum ADPU Length Accepted: ");
4967
4968         /* segmentationSupported */
4969         offset = fApplicationTypesEnumerated (tvb, tree, offset,
4970                 "Segmentation Supported: ", BACnetSegmentation);
4971
4972         /* vendor ID */
4973         return fUnsignedTag (tvb, tree, offset, "Vendor ID: ");
4974 }
4975
4976 static guint
4977 fIHaveRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
4978 {
4979         /* BACnetDeviceIdentifier */
4980         offset = fApplicationTypes (tvb, tree, offset, "Device Identifier: ");
4981
4982         /* BACnetObjectIdentifier */
4983         offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: ");
4984
4985         /* ObjectName */
4986         return fApplicationTypes (tvb, tree, offset, "Object Name: ");
4987
4988 }
4989
4990 static guint
4991 fWhoIsRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
4992 {
4993         guint lastoffset = 0;
4994
4995         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4996                 lastoffset = offset;
4997                 switch (fTagNo(tvb, offset)) {
4998                 case 0: /* DeviceInstanceRangeLowLimit Optional */
4999                         offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range Low Limit: ");
5000                         break;
5001                 case 1: /* DeviceInstanceRangeHighLimit Optional but required if DeviceInstanceRangeLowLimit is there */
5002                         offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range High Limit: ");
5003                         break;
5004                 default:
5005                         return offset;
5006                         break;
5007                 }
5008         }
5009         return offset;
5010 }
5011
5012 static guint
5013 fUnconfirmedServiceRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
5014 {
5015         if (tvb_length_remaining(tvb,offset) <= 0)
5016                 return offset;
5017
5018         switch (service_choice) {
5019         case 0: /* I-Am-Request */
5020                 offset = fIAmRequest  (tvb, tree, offset);
5021                 break;
5022         case 1: /* i-Have Request */
5023                 offset = fIHaveRequest  (tvb, tree, offset);
5024         break;
5025         case 2: /* unconfirmedCOVNotification */
5026                 offset = fUnconfirmedCOVNotificationRequest (tvb, tree, offset);
5027                 break;
5028         case 3: /* unconfirmedEventNotification */
5029                 offset = fUnconfirmedEventNotificationRequest (tvb, tree, offset);
5030                 break;
5031         case 4: /* unconfirmedPrivateTransfer */
5032                 offset = fUnconfirmedPrivateTransferRequest(tvb, tree, offset);
5033                 break;
5034         case 5: /* unconfirmedTextMessage */
5035                 offset = fUnconfirmedTextMessageRequest(tvb, tree, offset);
5036                 break;
5037         case 6: /* timeSynchronization */
5038                 offset = fTimeSynchronizationRequest  (tvb, tree, offset);
5039                 break;
5040         case 7: /* who-Has */
5041                 offset = fWhoHas (tvb, tree, offset);
5042                 break;
5043         case 8: /* who-Is */
5044                 offset = fWhoIsRequest  (tvb, tree, offset);
5045                 break;
5046         case 9: /* utcTimeSynchronization */
5047                 offset = fUTCTimeSynchronizationRequest  (tvb, tree, offset);
5048                 break;
5049         default:
5050                 break;
5051         }
5052         return offset;
5053 }
5054
5055 static guint
5056 fStartConfirmed(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset, guint8 ack,
5057                                 gint *svc, proto_item **tt)
5058 {
5059         proto_item *tc;
5060         proto_tree *bacapp_tree_control;
5061         gint tmp, bacapp_type;
5062         guint extra = 2;
5063
5064         bacapp_seq = 0;
5065         tmp = (gint) tvb_get_guint8(tvb, offset);
5066         bacapp_type = (tmp >> 4) & 0x0f;
5067         bacapp_flags = tmp & 0x0f;
5068
5069         if (ack == 0) {
5070                 extra = 3;
5071         }
5072         *svc = (gint) tvb_get_guint8(tvb, offset+extra);
5073         if (bacapp_flags & 0x08)
5074                 *svc = (gint) tvb_get_guint8(tvb, offset+extra+2);
5075
5076     proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
5077         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_pduflags, tvb, offset, 1, TRUE);
5078         bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp_control);
5079
5080     proto_tree_add_item(bacapp_tree_control, hf_bacapp_SEG, tvb, offset, 1, TRUE);
5081     proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, offset, 1, TRUE);
5082         if (ack == 0) /* The following are for ConfirmedRequest, not Complex ack */
5083         {
5084             proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, offset++, 1, TRUE);
5085                 proto_tree_add_item(bacapp_tree, hf_bacapp_response_segments, tvb,
5086                                                         offset, 1, TRUE);
5087                 proto_tree_add_item(bacapp_tree, hf_bacapp_max_adpu_size, tvb,
5088                                                         offset, 1, TRUE);
5089         }
5090     offset++;
5091     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
5092     if (bacapp_flags & 0x08) {
5093         bacapp_seq = tvb_get_guint8(tvb, offset);
5094         proto_tree_add_item(bacapp_tree_control, hf_bacapp_sequence_number, tvb,
5095             offset++, 1, TRUE);
5096         proto_tree_add_item(bacapp_tree_control, hf_bacapp_window_size, tvb,
5097             offset++, 1, TRUE);
5098     }
5099     *tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
5100         offset++, 1, TRUE);
5101         return offset;
5102 }
5103
5104 static guint
5105 fConfirmedRequestPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5106 {       /* BACnet-Confirmed-Request */
5107         /* ASHRAE 135-2001 20.1.2 */
5108         gint svc;
5109         proto_item *tt = 0;
5110
5111         offset = fStartConfirmed(tvb, bacapp_tree, offset, 0, &svc, &tt);
5112         if (bacapp_seq > 0) /* Can't handle continuation segments, so just treat as data */
5113         {
5114                 proto_tree_add_text(bacapp_tree, tvb, offset, 0, "(continuation)");
5115                 return offset;
5116         }
5117         else
5118         {
5119                 /* Service Request follows... Variable Encoding 20.2ff */
5120                 return fConfirmedServiceRequest (tvb, bacapp_tree, offset, svc);
5121         }
5122 }
5123
5124 static guint
5125 fUnconfirmedRequestPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5126 {       /* BACnet-Unconfirmed-Request-PDU */
5127         /* ASHRAE 135-2001 20.1.3 */
5128
5129         gint tmp;
5130
5131     proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
5132
5133     tmp = tvb_get_guint8(tvb, offset);
5134     proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb,
5135             offset++, 1, TRUE);
5136     /* Service Request follows... Variable Encoding 20.2ff */
5137     return fUnconfirmedServiceRequest  (tvb, bacapp_tree, offset, tmp);
5138 }
5139
5140 static guint
5141 fSimpleAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5142 {       /* BACnet-Simple-Ack-PDU */
5143         /* ASHRAE 135-2001 20.1.4 */
5144
5145         proto_item *tc;
5146
5147         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
5148
5149     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5150         offset++, 1, TRUE);
5151     proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
5152         offset++, 1, TRUE);
5153         return offset;
5154 }
5155
5156 static guint
5157 fComplexAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5158 {       /* BACnet-Complex-Ack-PDU */
5159         /* ASHRAE 135-2001 20.1.5 */
5160         gint svc;
5161         proto_item *tt = 0;
5162
5163         offset = fStartConfirmed(tvb, bacapp_tree, offset, 1, &svc, &tt);
5164
5165         if (bacapp_seq > 0) /* Can't handle continuation segments, so just treat as data */
5166         {
5167                 proto_tree_add_text(bacapp_tree, tvb, offset, 0, "(continuation)");
5168                 return offset;
5169         }
5170         else
5171         {
5172             /* Service ACK follows... */
5173                 return fConfirmedServiceAck (tvb, bacapp_tree, offset, svc);
5174         }
5175 }
5176
5177
5178 static guint
5179 fSegmentAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5180 {       /* BACnet-SegmentAck-PDU */
5181         /* ASHRAE 135-2001 20.1.6 */
5182
5183         proto_item *tc;
5184         proto_tree *bacapp_tree_control;
5185
5186     tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
5187     bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
5188
5189     proto_tree_add_item(bacapp_tree, hf_bacapp_NAK, tvb, offset, 1, TRUE);
5190     proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, offset++, 1, TRUE);
5191     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5192         offset++, 1, TRUE);
5193     proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
5194             offset++, 1, TRUE);
5195     proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
5196             offset++, 1, TRUE);
5197         return offset;
5198 }
5199
5200 static guint fContextTaggedError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5201 {
5202     guint8 tag_info = 0;
5203     guint8 parsed_tag = 0;
5204     guint32 lvt = 0;
5205     offset += fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt);
5206     offset = fError(tvb, tree, offset);
5207     return offset + fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt);
5208 }
5209
5210 static guint
5211 fConfirmedPrivateTransferError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5212 {
5213         guint lastoffset = 0;
5214         guint8 tag_no = 0, tag_info = 0;
5215         guint lvt = 0;
5216
5217         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
5218                 lastoffset = offset;
5219                 switch (fTagNo(tvb, offset)) {
5220                 case 0: /* errorType */
5221                         offset = fContextTaggedError(tvb,tree,offset);
5222                         break;
5223                 case 1: /* vendorID */
5224                         offset = fUnsignedTag (tvb,tree,offset,"vendor ID: ");
5225                         break;
5226                 case 2: /* serviceNumber */
5227                         offset = fUnsignedTag (tvb,tree,offset,"service Number: ");
5228                         break;
5229         case 3: /* errorParameters */
5230                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
5231             offset = fAbstractSyntaxNType (tvb, tree, offset);
5232                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
5233             break;
5234                 default:
5235                         return offset;
5236                 }
5237         }
5238         return offset;
5239 }
5240
5241 static guint
5242 fCreateObjectError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5243 {
5244         guint lastoffset = 0;
5245
5246         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
5247                 lastoffset = offset;
5248                 switch (fTagNo(tvb, offset)) {
5249                 case 0: /* errorType */
5250                         offset = fContextTaggedError(tvb,tree,offset);
5251                         break;
5252                 case 1: /* firstFailedElementNumber */
5253                         offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
5254                         break;
5255                 default:
5256                         return offset;
5257                 }
5258         }
5259         return offset;
5260 }
5261
5262 static guint
5263 fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5264 {
5265         /* Identical to CreateObjectError */
5266         return fCreateObjectError(tvb, tree, offset);
5267 }
5268
5269 static guint
5270 fVTCloseError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5271 {
5272         guint8 tag_no = 0, tag_info = 0;
5273         guint32 lvt = 0;
5274
5275         if (fTagNo(tvb, offset) == 0)
5276         {
5277                 /* errorType */
5278                 offset = fContextTaggedError(tvb,tree,offset);
5279                 if (fTagNo(tvb, offset) == 1)
5280                 {
5281                         /* listOfVTSessionIdentifiers [OPTIONAL] */
5282                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
5283                         offset = fVtCloseRequest (tvb, tree, offset);
5284                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
5285                 }
5286         }
5287         /* should report bad packet if initial tag wasn't 0 */
5288         return offset;
5289 }
5290
5291 static guint
5292 fWritePropertyMultipleError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5293 {
5294         guint lastoffset = 0;
5295         guint8 tag_no = 0, tag_info = 0;
5296         guint32 lvt = 0;
5297
5298         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
5299                 lastoffset = offset;
5300                 switch (fTagNo(tvb, offset)) {
5301                 case 0: /* errorType */
5302                         offset = fContextTaggedError(tvb,tree,offset);
5303                         break;
5304                 case 1: /* firstFailedWriteAttempt */
5305                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
5306                         offset = fBACnetObjectPropertyReference(tvb, tree, offset);
5307                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
5308                         break;
5309                 default:
5310                         return offset;
5311                 }
5312         }
5313         return offset;
5314 }
5315
5316 static guint
5317 fError (tvbuff_t *tvb, proto_tree *tree, guint offset)
5318 {
5319     offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset,
5320         "error Class: ", BACnetErrorClass, 64);
5321     return fApplicationTypesEnumeratedSplit (tvb, tree, offset,
5322         "error Code: ", BACnetErrorCode, 256);
5323 }
5324
5325 static guint
5326 fBACnetError (tvbuff_t *tvb, proto_tree *tree, guint offset, guint service)
5327 {
5328     switch (service) {
5329     case 8:  /* no break here !!!! */
5330     case 9:
5331         offset = fChangeListError (tvb, tree, offset);
5332         break;
5333     case 10:
5334         offset = fCreateObjectError (tvb,tree,offset);
5335         break;
5336     case 16:
5337         offset = fWritePropertyMultipleError (tvb,tree,offset);
5338         break;
5339     case 18:
5340         offset = fConfirmedPrivateTransferError (tvb,tree,offset);
5341     case 22:
5342         offset = fVTCloseError (tvb,tree,offset);
5343     default:
5344         return fError (tvb, tree, offset);
5345         break;
5346     }
5347     return offset;
5348 }
5349
5350 static guint
5351 fErrorPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5352 {       /* BACnet-Error-PDU */
5353         /* ASHRAE 135-2001 20.1.7 */
5354
5355         proto_item *tc, *tt;
5356         proto_tree *bacapp_tree_control;
5357     guint8 tmp;
5358
5359     tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
5360     bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
5361
5362     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5363         offset++, 1, TRUE);
5364     tmp = tvb_get_guint8(tvb, offset);
5365     tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
5366         offset++, 1, TRUE);
5367     /* Error Handling follows... */
5368     return fBACnetError (tvb, bacapp_tree, offset, tmp);
5369 }
5370
5371 static guint
5372 fRejectPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5373 {       /* BACnet-Reject-PDU */
5374         /* ASHRAE 135-2001 20.1.8 */
5375
5376         proto_item *tc;
5377         proto_tree *bacapp_tree_control;
5378
5379     tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
5380     bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
5381
5382     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5383         offset++, 1, TRUE);
5384     proto_tree_add_item(bacapp_tree, hf_BACnetRejectReason, tvb,
5385         offset++, 1, TRUE);
5386         return offset;
5387 }
5388
5389 static guint
5390 fAbortPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5391 {       /* BACnet-Abort-PDU */
5392         /* ASHRAE 135-2001 20.1.9 */
5393
5394         proto_item *tc;
5395         proto_tree *bacapp_tree_control;
5396
5397     tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
5398     bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
5399
5400     proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, offset++, 1, TRUE);
5401     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5402         offset++, 1, TRUE);
5403     proto_tree_add_item(bacapp_tree, hf_BACnetAbortReason, tvb,
5404         offset++, 1, TRUE);
5405         return offset;
5406 }
5407
5408 void
5409 dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5410 {
5411         gint8 tmp, bacapp_type;
5412         tvbuff_t *next_tvb;
5413         guint offset = 0;
5414         guint8 bacapp_service, bacapp_reason;
5415         guint8 bacapp_invoke_id;
5416         proto_item *ti;
5417         proto_tree *bacapp_tree;
5418
5419         if (check_col(pinfo->cinfo, COL_PROTOCOL))
5420                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU");
5421         if (check_col(pinfo->cinfo, COL_INFO))
5422                 col_add_str(pinfo->cinfo, COL_INFO, "BACnet APDU ");
5423
5424         tmp = (gint) tvb_get_guint8(tvb, 0);
5425         bacapp_type = (tmp >> 4) & 0x0f;
5426
5427         /* show some descriptive text in the INFO column */
5428         if (check_col(pinfo->cinfo, COL_INFO))
5429         {
5430                 col_clear(pinfo->cinfo, COL_INFO);
5431                 col_add_str(pinfo->cinfo, COL_INFO,
5432                         val_to_str(bacapp_type, BACnetTypeName, "#### unknown APDU ##### "));
5433                 switch (bacapp_type)
5434                 {
5435                         case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
5436                                 /* segmented messages have 2 additional bytes */
5437                                 if (tmp & BACAPP_SEGMENTED_REQUEST)
5438                                 {
5439                                         bacapp_invoke_id = tvb_get_guint8(tvb, offset + 4);
5440                                         bacapp_service = tvb_get_guint8(tvb, offset + 5);
5441                                 }
5442                                 else
5443                                 {
5444                                         bacapp_invoke_id = tvb_get_guint8(tvb, offset + 2);
5445                                         bacapp_service = tvb_get_guint8(tvb, offset + 3);
5446                                 }
5447                                 col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s",
5448                                         bacapp_invoke_id,
5449                                         val_to_str(bacapp_service,
5450                                                 BACnetConfirmedServiceChoice,
5451                                                 bacapp_unknown_service_str));
5452                                 break;
5453                         case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:
5454                                 bacapp_service = tvb_get_guint8(tvb, offset + 1);
5455                                 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
5456                                         val_to_str(bacapp_service,
5457                                                 BACnetUnconfirmedServiceChoice,
5458                                                 bacapp_unknown_service_str));
5459                                 break;
5460                         case BACAPP_TYPE_SIMPLE_ACK:
5461                                 bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
5462                                 bacapp_service = tvb_get_guint8(tvb, offset + 2);
5463                                 col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s",
5464                                         bacapp_invoke_id,
5465                                         val_to_str(bacapp_service,
5466                                                 BACnetConfirmedServiceChoice,
5467                                                 bacapp_unknown_service_str));
5468                                 break;
5469                         case BACAPP_TYPE_COMPLEX_ACK:
5470                                 /* segmented messages have 2 additional bytes */
5471                                 if (tmp & BACAPP_SEGMENTED_REQUEST)
5472                                 {
5473                                         bacapp_invoke_id = tvb_get_guint8(tvb, offset + 3);
5474                                         bacapp_service = tvb_get_guint8(tvb, offset + 4);
5475                                 }
5476                                 else
5477                                 {
5478                                         bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
5479                                         bacapp_service = tvb_get_guint8(tvb, offset + 2);
5480                                 }
5481                                 col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s",
5482                                         bacapp_invoke_id,
5483                                         val_to_str(bacapp_service,
5484                                                 BACnetConfirmedServiceChoice,
5485                                                 bacapp_unknown_service_str));
5486                                 break;
5487                         case BACAPP_TYPE_SEGMENT_ACK:
5488                                 /* nothing more to add */
5489                                 break;
5490                         case BACAPP_TYPE_ERROR:
5491                                 bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
5492                                 bacapp_service = tvb_get_guint8(tvb, offset + 2);
5493                                 col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s",
5494                                         bacapp_invoke_id,
5495                                         val_to_str(bacapp_service,
5496                                                 BACnetConfirmedServiceChoice,
5497                                                 bacapp_unknown_service_str));
5498                                 break;
5499                         case BACAPP_TYPE_REJECT:
5500                                 bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
5501                                 bacapp_reason = tvb_get_guint8(tvb, offset + 2);
5502                                 col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s",
5503                                         bacapp_invoke_id,
5504                                         val_to_split_str(bacapp_reason,
5505                                                 64,
5506                                                 BACnetRejectReason,
5507                                                 ASHRAE_Reserved_Fmt,
5508                                                 Vendor_Proprietary_Fmt));
5509                                 break;
5510                         case BACAPP_TYPE_ABORT:
5511                                 bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
5512                                 bacapp_reason = tvb_get_guint8(tvb, offset + 2);
5513                                 col_append_fstr(pinfo->cinfo, COL_INFO, "[invoke:%d]: %s",
5514                                         bacapp_invoke_id,
5515                                         val_to_split_str(bacapp_reason,
5516                                                 64,
5517                                                 BACnetAbortReason,
5518                                                 ASHRAE_Reserved_Fmt,
5519                                                 Vendor_Proprietary_Fmt));
5520                                 break;
5521                         /* UNKNOWN */
5522                         default:
5523                                 /* nothing more to add */
5524                                 break;
5525                 }
5526         }
5527
5528     if (tree) {
5529                 ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
5530                 bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
5531
5532                 /* ASHRAE 135-2001 20.1.1 */
5533         switch (bacapp_type) {
5534         case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:     /* BACnet-Confirmed-Service-Request */
5535                 offset = fConfirmedRequestPDU(tvb, bacapp_tree, offset);
5536                 break;
5537         case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:   /* BACnet-Unconfirmed-Request-PDU */
5538                 offset = fUnconfirmedRequestPDU(tvb, bacapp_tree, offset);
5539                 break;
5540         case BACAPP_TYPE_SIMPLE_ACK:    /* BACnet-Simple-Ack-PDU */
5541                 offset = fSimpleAckPDU(tvb, bacapp_tree, offset);
5542                 break;
5543         case BACAPP_TYPE_COMPLEX_ACK:   /* BACnet-Complex-Ack-PDU */
5544                 offset = fComplexAckPDU(tvb, bacapp_tree, offset);
5545                 break;
5546         case BACAPP_TYPE_SEGMENT_ACK:   /* BACnet-SegmentAck-PDU */
5547                 offset = fSegmentAckPDU(tvb, bacapp_tree, offset);
5548                 break;
5549         case BACAPP_TYPE_ERROR: /* BACnet-Error-PDU */
5550                 offset = fErrorPDU(tvb, bacapp_tree, offset);
5551                 break;
5552         case BACAPP_TYPE_REJECT:        /* BACnet-Reject-PDU */
5553                 offset = fRejectPDU(tvb, bacapp_tree, offset);
5554                 break;
5555         case BACAPP_TYPE_ABORT: /* BACnet-Abort-PDU */
5556                 offset = fAbortPDU(tvb, bacapp_tree, offset);
5557                 break;
5558         }
5559     }
5560
5561         next_tvb = tvb_new_subset(tvb,offset,-1,tvb_length_remaining(tvb,offset));
5562         call_dissector(data_handle,next_tvb, pinfo, tree);
5563 }
5564
5565 void
5566 proto_register_bacapp(void)
5567 {
5568         static hf_register_info hf[] = {
5569                 { &hf_bacapp_type,
5570                         { "APDU Type",           "bacapp.type",
5571                         FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, "APDU Type", HFILL }
5572                 },
5573                 { &hf_bacapp_pduflags,
5574                         { "PDU Flags",                  "bacapp.pduflags",
5575                         FT_UINT8, BASE_HEX, NULL, 0x0f, "PDU Flags", HFILL }
5576                 },
5577                 { &hf_bacapp_SEG,
5578                         { "Segmented Request",           "bacapp.segmented_request",
5579                         FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, "Segmented Request", HFILL }
5580                 },
5581                 { &hf_bacapp_MOR,
5582                         { "More Segments",           "bacapp.more_segments",
5583                         FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL }
5584                 },
5585                 { &hf_bacapp_SA,
5586                         { "SA",           "bacapp.SA",
5587                         FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL }
5588                 },
5589                 { &hf_bacapp_max_adpu_size,
5590                         { "Size of Maximum ADPU accepted",           "bacapp.max_adpu_size",
5591                         FT_UINT8, BASE_DEC, VALS(BACnetMaxAPDULengthAccepted), 0x0f, "Size of Maximum ADPU accepted", HFILL }
5592                 },
5593                 { &hf_bacapp_response_segments,
5594                         { "Max Response Segments accepted",           "bacapp.response_segments",
5595                         FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0x70, "Max Response Segments accepted", HFILL }
5596                 },
5597                 { &hf_bacapp_objectType,
5598                         { "Object Type",           "bacapp.objectType",
5599                         FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, "Object Type", HFILL }
5600                 },
5601                 { &hf_bacapp_instanceNumber,
5602                         { "Instance Number",           "bacapp.instance_number",
5603                         FT_UINT32, BASE_DEC, NULL, 0x003fffff, "Instance Number", HFILL }
5604                 },
5605                 { &hf_bacapp_invoke_id,
5606                         { "Invoke ID",           "bacapp.invoke_id",
5607                         FT_UINT8, BASE_DEC, NULL, 0, "Invoke ID", HFILL }
5608                 },
5609                 { &hf_bacapp_sequence_number,
5610                         { "Sequence Number",           "bacapp.sequence_number",
5611                         FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL }
5612                 },
5613                 { &hf_bacapp_window_size,
5614                         { "Proposed Window Size",           "bacapp.window_size",
5615                         FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL }
5616                 },
5617                 { &hf_bacapp_service,
5618                         { "Service Choice",           "bacapp.confirmed_service",
5619                         FT_UINT8, BASE_DEC, VALS(BACnetConfirmedServiceChoice), 0x00, "Service Choice", HFILL }
5620                 },
5621                 { &hf_bacapp_uservice,
5622                         { "Unconfirmed Service Choice",           "bacapp.unconfirmed_service",
5623                         FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, "Unconfirmed Service Choice", HFILL }
5624                 },
5625                 { &hf_bacapp_NAK,
5626                         { "NAK",           "bacapp.NAK",
5627                         FT_BOOLEAN, 8, NULL, 0x02, "negativ ACK", HFILL }
5628                 },
5629                 { &hf_bacapp_SRV,
5630                         { "SRV",           "bacapp.SRV",
5631                         FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL }
5632                 },
5633                 { &hf_BACnetRejectReason,
5634                         { "Reject Reason",           "bacapp.reject_reason",
5635                         FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, "Reject Reason", HFILL }
5636                 },
5637                 { &hf_BACnetAbortReason,
5638                         { "Abort Reason",           "bacapp.abort_reason",
5639                         FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 0x00, "Abort Reason", HFILL }
5640                 },
5641                 { &hf_bacapp_vpart,
5642                         { "BACnet APDU variable part:",           "bacapp.variable_part",
5643                         FT_NONE, 0, NULL, 0, "BACnet APDU variable part", HFILL }
5644                 },
5645                 { &hf_bacapp_tag,
5646                         { "BACnet Tag",
5647                         "bacapp.tag",
5648                         FT_BYTES, BASE_HEX, NULL, 0,
5649                         "BACnet Tag", HFILL }
5650                 },
5651                 { &hf_BACnetApplicationTagNumber,
5652                         { "Application Tag Number",
5653                         "bacapp.application_tag_number",
5654                         FT_UINT8, BASE_DEC, VALS(&BACnetApplicationTagNumber), 0xF0,
5655                         "Application Tag Number", HFILL }
5656                 },
5657                 { &hf_BACnetContextTagNumber,
5658                         { "Context Tag Number",
5659                         "bacapp.context_tag_number",
5660                         FT_UINT8, BASE_DEC, NULL, 0xF0,
5661                         "Context Tag Number", HFILL }
5662                 },
5663                 { &hf_BACnetExtendedTagNumber,
5664                         { "Extended Tag Number",
5665                         "bacapp.extended_tag_number",
5666                         FT_UINT8, BASE_DEC, NULL, 0,
5667                         "Extended Tag Number", HFILL }
5668                 },
5669                 { &hf_BACnetNamedTag,
5670                         { "Named Tag",
5671                         "bacapp.named_tag",
5672                         FT_UINT8, BASE_DEC, VALS(&BACnetTagNames), 0x07,
5673                         "Named Tag", HFILL }
5674                 },
5675                 { &hf_BACnetCharacterSet,
5676                         { "String Character Set",
5677                         "bacapp.string_character_set",
5678                         FT_UINT8, BASE_DEC, VALS(&BACnetCharacterSet),0,
5679                         "String Character Set", HFILL }
5680                 },
5681                 { &hf_BACnetTagClass,
5682                         { "Tag Class",           "bacapp.tag_class",
5683                         FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, "Tag Class", HFILL }
5684                 },
5685                 { &hf_bacapp_tag_lvt,
5686                         { "Length Value Type",
5687                         "bacapp.LVT",
5688                         FT_UINT8, BASE_DEC, NULL, 0,
5689                         "Length Value Type", HFILL }
5690                 },
5691                 { &hf_bacapp_tag_value8,
5692                         { "Tag Value",
5693                         "bacapp.tag_value8",
5694                         FT_UINT8, BASE_DEC, NULL, 0,
5695                         "Tag Value", HFILL }
5696                 },
5697                 { &hf_bacapp_tag_value16,
5698                         { "Tag Value 16-bit",
5699                         "bacapp.tag_value16",
5700                         FT_UINT16, BASE_DEC, NULL, 0,
5701                         "Tag Value 16-bit", HFILL }
5702                 },
5703                 { &hf_bacapp_tag_value32,
5704                         { "Tag Value 32-bit",
5705                         "bacapp.tag_value32",
5706                         FT_UINT32, BASE_DEC, NULL, 0,
5707                         "Tag Value 32-bit", HFILL }
5708                 },
5709                 { &hf_bacapp_tag_ProcessId,
5710                         { "ProcessIdentifier",           "bacapp.processId",
5711                         FT_UINT32, BASE_DEC, NULL, 0, "Process Identifier", HFILL }
5712                 },
5713                 { &hf_bacapp_tag_initiatingObjectType,
5714                         { "ObjectType",           "bacapp.objectType",
5715                         FT_UINT16, BASE_DEC, VALS(BACnetObjectType), 0x00, "Object Type", HFILL }
5716                 }
5717         };
5718         static gint *ett[] = {
5719                 &ett_bacapp,
5720                 &ett_bacapp_control,
5721                 &ett_bacapp_tag,
5722                 &ett_bacapp_list,
5723                 &ett_bacapp_value
5724         };
5725         proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU",
5726             "BACapp", "bacapp");
5727
5728         proto_register_field_array(proto_bacapp, hf, array_length(hf));
5729         proto_register_subtree_array(ett, array_length(ett));
5730         register_dissector("bacapp", dissect_bacapp, proto_bacapp);
5731
5732 }
5733
5734 void
5735 proto_reg_handoff_bacapp(void)
5736 {
5737         data_handle = find_dissector("data");
5738 }
5739
5740 guint32
5741 fConvertXXXtoUTF8 (const guint8 *in, size_t *inbytesleft, guint8 *out, size_t *outbytesleft, const gchar *fromcoding)
5742 {  /* I don't want to let in and out be modified */
5743 #ifdef HAVE_CONFIG_H
5744 #if HAVE_ICONV
5745         guint32 i;
5746         iconv_t icd;
5747         const char *inp = in;
5748         guint8 *outp = out;
5749         const char **inpp = &inp;
5750         guint8 **outpp = &outp;
5751
5752     if ((icd = iconv_open ("UTF-8", fromcoding)) != (iconv_t) -1) {
5753         i = iconv (icd, (char**) inpp, inbytesleft, (char**) outpp, outbytesleft);
5754                 *outpp[0] = '\0';
5755         iconv_close (icd);
5756         return i;
5757     }
5758
5759 #endif
5760 #endif
5761
5762     memcpy (out, in, *inbytesleft);
5763     out[*inbytesleft] = '\0';
5764         *outbytesleft -= *inbytesleft;
5765     *inbytesleft = 0;
5766
5767     return 0;
5768 }
5769