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