573282956701dadc0fd42750c91e6c76fd6e04e7
[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@abmlinux.org>, FH Dortmund
4  * Enhanced by Steve Karg, 2005, <skarg@users.sourceforge.net>, Atlanta
5  * Enhanced by Herbert Lischka, 2005, <lischka@kieback-peter.de>, Berlin
6  *
7  * $Id$
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
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 static const value_string
160 BACnetAbortReason [] = {
161         {0,"other"},
162         {1,"buffer-overflow"},
163         {2,"invalid-apdu-in-this-state"},
164         {3,"preempted-by-higher-priority-task"},
165         {4,"segmentation-not-supported"},
166         {0,NULL}
167 };
168
169 static const value_string
170 BACnetLifeSafetyMode [] = {
171         {0,"off"},
172         {1,"on"},
173         {2,"test"},
174         {3,"manned"},
175         {4,"unmanned"},
176         {5,"armed"},
177         {6,"disarmed"},
178         {7,"prearmed"},
179         {8,"slow"},
180         {9,"fast"},
181         {10,"disconnected"},
182         {11,"enabled"},
183         {12,"disabled"},
184         {13,"atomic-release-disabled"},
185         {14,"default"},
186         {0,NULL}
187 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
188    Enumerated values 256-65535 may be used by others subject to
189    procedures and constraints described in Clause 23. */
190 };
191
192 static const value_string
193 BACnetLifeSafetyOperation [] = {
194         {0,"none"},
195         {1,"silence"},
196         {2,"silence-audible"},
197         {3,"silence-visual"},
198         {4,"reset"},
199         {5,"reset-alarm"},
200         {6,"reset-fault"},
201         {7,"unsilence"},
202         {8,"unsilence-audible"},
203         {9,"unsilence-visual"},
204         {0,NULL}
205 /* Enumerated values 0-63 are reserved for definition by ASHRAE. 
206    Enumerated values 64-65535 may be used by others subject to 
207    procedures and constraints described in Clause 23. */
208 };
209
210 static const value_string
211 BACnetLimitEnable [] = {
212         {0,"lowLimitEnable"},
213         {1,"highLimitEnable"},
214         {0,NULL}
215 };
216
217 static const value_string
218 BACnetLifeSafetyState [] = {
219         {0,"quiet"},
220         {1,"pre-alarm"},
221         {2,"alarm"},
222         {3,"fault"},
223         {4,"fault-pre-alarm"},
224         {5,"fault-alarm"},
225         {6,"not-ready"},
226         {7,"active"},
227         {8,"tamper"},
228         {9,"test-alarm"},
229         {10,"test-active"},
230         {11,"test-fault"},
231         {12,"test-fault-alarm"},
232         {13,"holdup"},
233         {14,"duress"},
234         {15,"tamper-alarm"},
235         {16,"abnormal"},
236         {17,"emergency-power"},
237         {18,"delayed"},
238         {19,"blocked"},
239         {20,"local-alarm"},
240         {21,"general-alarm"},
241         {22,"supervisory"},
242         {23,"test-supervisory"},
243         {0,NULL}
244 /* Enumerated values 0-255 are reserved for definition by ASHRAE. 
245    Enumerated values 256-65535 may be used by others subject to 
246    procedures and constraints described in Clause 23. */
247 };
248
249 static const value_string
250 BACnetConfirmedServiceChoice [] = {
251         {0,"acknowledgeAlarm"},
252         {1,"confirmedCOVNotification"},
253         {2,"confirmedEventNotification"},
254         {3,"getAlarmSummary"},
255         {4,"getEnrollmentSummary"},
256         {5,"subscribeCOV"},
257         {6,"atomicReadFile"},
258         {7,"atomicWriteFile"},
259         {8,"addListElement"},
260         {9,"removeListElement"},
261         {10,"createObject"},
262         {11,"deleteObject"},
263         {12,"readProperty"},
264         {13,"readPropertyConditional"},
265         {14,"readPropertyMultiple"},
266         {15,"writeProperty"},
267         {16,"writePropertyMultiple"},
268         {17,"deviceCommunicationControl"},
269         {18,"confirmedPrivateTransfer"},
270         {19,"confirmedTextMessage"},
271         {20,"reinitializeDevice"},
272         {21,"vtOpen"},
273         {22,"vtClose"},
274         {23,"vtData"},
275         {24,"authenticate"},
276         {25,"requestKey"},
277         {26,"readRange"},
278         {27,"lifeSafetyOperation"},
279         {28,"subscribeCOVProperty"},
280         {29,"getEventInformation"},
281         {30,"reserved by ASHRAE"},
282         {0, NULL}
283 };
284
285 static const value_string
286 BACnetReliability [] = {
287         {0,"no-fault-detected"},
288         {1,"no-sensor"},
289         {2,"over-range"},
290         {3,"under-range"},
291         {4,"open-loop"},
292         {5,"shorted-loop"},
293         {6,"no-output"},
294         {7,"unreliable-other"},
295         {8,"process-error"},
296         {9,"multi-state-fault"},
297         {0,NULL}
298 };
299
300 static const value_string
301 BACnetUnconfirmedServiceChoice [] = {
302         {0,"i-Am"},
303         {1,"i-Have"},
304         {2,"unconfirmedCOVNotification"},
305         {3,"unconfirmedEventNotification"},
306         {4,"unconfirmedPrivateTransfer"},
307         {5,"unconfirmedTextMessage"},
308         {6,"timeSynchronization"},
309         {7,"who-Has"},
310         {8,"who-Is"},
311         {9,"utcTimeSynchonization"},
312         {0,NULL}
313 };
314
315 static const value_string
316 BACnetUnconfirmedServiceRequest [] = {
317         {0,"i-Am-Request"},
318         {1,"i-Have-Request"},
319         {2,"unconfirmedCOVNotification-Request"},
320         {3,"unconfirmedEventNotification-Request"},
321         {4,"unconfirmedPrivateTransfer-Request"},
322         {5,"unconfirmedTextMessage-Request"},
323         {6,"timeSynchronization-Request"},
324         {7,"who-Has-Request"},
325         {8,"who-Is-Request"},
326         {9,"utcTimeSynchonization-Request"},
327         {0,NULL}
328 };
329
330 static const value_string
331 BACnetObjectType [] = {
332         {0,"analog-input object"},
333         {1,"analog-output object"},
334         {2,"analog-value object"},
335         {3,"binary-input object"},
336         {4,"binary-output object"},
337         {5,"binary-value object"},
338         {6,"calendar object"},
339         {7,"command object"},
340         {8,"device object"},
341         {9,"event-enrollment object"},
342         {10,"file object"},
343         {11,"group object"},
344         {12,"loop object"},
345         {13,"multi-state-input object"},
346         {14,"multi-state-output object"},
347         {15,"notification-class object"},
348         {16,"program object"},
349         {17,"schedule object"},
350         {18,"averaging object"},
351         {19,"multi-state-value object"},
352         {20,"trend-log object"},
353         {21,"life-safety-point object"},
354         {22,"life-safety-zone object"},
355         {23,"accumulator object"},
356         {24,"pulse-converter object"},
357         {0, NULL}
358 /* Enumerated values 0-127 are reserved for definition by ASHRAE.
359    Enumerated values 128-1023 may be used by others subject to
360    the procedures and constraints described in Clause 23. */
361 };
362
363 static const value_string
364 BACnetEngineeringUnits [] = {
365         {0,"Sq Meters"},
366         {1,"Sq Feet"},
367         {2,"Milliamperes"},
368         {3,"Amperes"},
369         {4,"Ohms"},
370         {5,"Volts"},
371         {6,"Kilovolts"},
372         {7,"Megavolts"},
373         {8,"Volt Amperes"},
374         {9,"Kilovolt Amperes"},
375         {10,"Megavolt Amperes"},
376         {11,"Volt Amperes Reactive"},
377         {12,"Kilovolt Amperes Reactive"},
378         {13,"Megavolt Amperes Ractive"},
379         {14,"Degrees Phase"},
380         {15,"Power Factor"},
381         {16,"Joules"},
382         {17,"Kilojoules"},
383         {18,"Watt Hours"},
384         {19,"Kilowatt Hours"},
385         {20,"BTUs"},
386         {21,"Therms"},
387         {22,"Ton Hours"},
388         {23,"Joules Per Kg Dry Air"},
389         {24,"BTUs Per Pound Dry Air"},
390         {25,"Cycles Per Hour"},
391         {26,"Cycles Per Minute"},
392         {27,"Hertz"},
393         {28,"Gramms Of Water Per Kilogram Dry Air"},
394         {29,"Relative Humidity"},
395         {30,"Millimeters"},
396         {31,"Meters"},
397         {32,"Inches"},
398         {33,"Feed"},
399         {34,"Watts Per Sq Foot"},
400         {35,"Watts Per Sq meter"},
401         {36,"Lumens"},
402         {37,"Lux"},
403         {38,"Foot Candels"},
404         {39,"Kilograms"},
405         {40,"Pounds Mass"},
406         {41,"Tons"},
407         {42,"Kgs per Second"},
408         {43,"Kgs Per Minute"},
409         {44,"Kgs Per Hour"},
410         {45,"Pounds Mass Per Minute"},
411         {46,"Pounds Mass Per Hour"},
412         {47,"Watt"},
413         {48,"Kilowatts"},
414         {49,"Megawatts"},
415         {50,"BTUs Per Hour"},
416         {51,"Horsepower"},
417         {52,"Tons Refrigeration"},
418         {53,"Pascals"},
419         {54,"Kilopascals"},
420         {55,"Bars"},
421         {56,"Pounds Force Per Square Inch"},
422         {57,"Centimeters Of Water"},
423         {58,"Inches Of Water"},
424         {59,"Millimeters Of Mercury"},
425         {60,"Centimeters Of Mercury"},
426         {61,"Inches Of Mercury"},
427         {62,"Degrees Celsius"},
428         {63,"Degress Kelvin"},
429         {64,"Degrees Fahrenheit"},
430         {65,"Degree Days Celsius"},
431         {66,"Degree Days Fahrenheit"},
432         {67,"Years"},
433         {68,"Months"},
434         {69,"Weeks"},
435         {70,"Days"},
436         {71,"Hours"},
437         {72,"Minutes"},
438         {73,"Seconds"},
439         {74,"Meters Per Second"},
440         {75,"Kilometers Per Hour"},
441         {76,"Feed Per Second"},
442         {77,"Feet Per Minute"},
443         {78,"Miles Per Hour"},
444         {79,"Cubic Feet"},
445         {80,"Cubic Meters"},
446         {81,"Imperial Gallons"},
447         {82,"Liters"},
448         {83,"US Gallons"},
449         {84,"Cubic Feet Per Minute"},
450         {85,"Cubic Meters Per Second"},
451         {86,"Imperial Gallons Per Minute"},
452         {87,"Liters Per Second"},
453         {88,"Liters Per Minute"},
454         {89,"US Gallons Per Minute"},
455         {90,"Degrees Angular"},
456         {91,"Degrees Celsius Per Hour"},
457         {92,"Degrees Celsius Per Minute"},
458         {93,"Degrees Fahrenheit Per Hour"},
459         {94,"Degrees Fahrenheit Per Minute"},
460         {95,"No Units"},
461         {96,"Parts Per Million"},
462         {97,"Parts Per Billion"},
463         {98,"Percent"},
464         {99,"Pecent Per Second"},
465         {100,"Per Minute"},
466         {101,"Per Second"},
467         {102,"Psi Per Degree Fahrenheit"},
468         {103,"Radians"},
469         {104,"Revolutions Per Min"},
470         {105,"Currency1"},
471         {106,"Currency2"},
472         {107,"Currency3"},
473         {108,"Currency4"},
474         {109,"Currency5"},
475         {110,"Currency6"},
476         {111,"Currency7"},
477         {112,"Currency8"},
478         {113,"Currency9"},
479         {114,"Currency10"},
480         {115,"Sq Inches"},
481         {116,"Sq Centimeters"},
482         {117,"BTUs Per Pound"},
483         {118,"Centimeters"},
484         {119,"Pounds Mass Per Second"},
485         {120,"Delta Degrees Fahrenheit"},
486         {121,"Delta Degrees Kelvin"},
487         {122,"Kilohms"},
488         {123,"Megohms"},
489         {124,"Millivolts"},
490         {125,"Kilojoules Per Kg"},
491         {126,"Megajoules"},
492         {127,"Joules Per Degree Kelvin"},
493         {128,"Joules Per Kg Degree Kelvin"},
494         {129,"Kilohertz"},
495         {130,"Megahertz"},
496         {131,"Per Hour"},
497         {132,"Milliwatts"},
498         {133,"Hectopascals"},
499         {134,"Millibars"},
500         {135,"Cubic Meters Per Hour"},
501         {136,"Liters Per Hour"},
502         {137,"KWatt Hours Per Square Meter"},
503         {138,"KWatt Hours Per Square Foot"},
504         {139,"Megajoules Per Square Meter"},
505         {140,"Megajoules Per Square Foot"},
506         {141,"Watts Per Sq Meter Degree Kelvin"},
507         {142,"Cubic Feet Per Second"},
508         {143,"Percent Obstruction Per Foot"},
509         {144,"Percent Obstruction Per Meter"},
510         {145,"milliohms"},
511         {146,"megawatt-hours"},
512         {147,"kilo-btus"},
513         {148,"mega-btus"},
514         {149,"kilojoules-per-kilogram-dry-air"},
515         {150,"megajoules-per-kilogram-dry-air"},
516         {151,"kilojoules-per-degree-Kelvin"},
517         {152,"megajoules-per-degree-Kelvin"},
518         {153,"newton"},
519         {154,"grams-per-second"},
520         {155,"grams-per-minute"},
521         {156,"tons-per-hour"},
522         {157,"kilo-btus-per-hour"},
523         {158,"hundredths-seconds"},
524         {159,"milliseconds"},
525         {160,"newton-meters"},
526         {161,"millimeters-per-second"},
527         {162,"millimeters-per-minute"},
528         {163,"meters-per-minute"},
529         {164,"meters-per-hour"},
530         {165,"cubic-meters-per-minute"},
531         {166,"meters-per-second-per-second"},
532         {167,"amperes-per-meter"},
533         {168,"amperes-per-square-meter"},
534         {169,"ampere-square-meters"},
535         {170,"farads"},
536         {171,"henrys"},
537         {172,"ohm-meters"},
538         {173,"siemens"},
539         {174,"siemens-per-meter"},
540         {175,"teslas"},
541         {176,"volts-per-degree-Kelvin"},
542         {177,"volts-per-meter"},
543         {178,"webers"},
544         {179,"candelas"},
545         {180,"candelas-per-square-meter"},
546         {181,"degrees-Kelvin-per-hour"},
547         {182,"degrees-Kelvin-per-minute"},
548         {183,"joule-seconds"},
549         {184,"radians-per-second"},
550         {185,"square-meters-per-Newton"},
551         {186,"kilograms-per-cubic-meter"},
552         {187,"newton-seconds"},
553         {188,"newtons-per-meter"},
554         {189,"watts-per-meter-per-degree-Kelvin"},
555         {0,NULL}
556 /* Enumerated values 0-255 are reserved for definition by ASHRAE. 
557    Enumerated values 256-65535 may be used by others subject to 
558    the procedures and constraints described in Clause 23. */
559 };
560
561 static const value_string
562 BACnetErrorCode [] = {
563         {0,"other"},
564         {1,"authentication-failed"},
565         {2,"character-set-not-supported"},
566         {3,"configuration-in-progress"},
567         {4,"device-busy"},
568         {5,"file-access-denied"},
569         {6,"incompatible-security-levels"},
570         {7,"inconsistent-parameters"},
571         {8,"inconsistent-selection-criterion"},
572         {9,"invalid-data-type"},
573         {10,"invalid-file-access-method"},
574         {11,"invalid-file-start-position"},
575         {12,"invalid-operator-name"},
576         {13,"invalid-parameter-data-type"},
577         {14,"invalid-time-stamp"},
578         {15,"key-generation-error"},
579         {16,"missing-required-parameter"},
580         {17,"no-objects-of-specified-type"},
581         {18,"no-space-for-object"},
582         {19,"no-space-to-add-list-element"},
583         {20,"no-space-to-write-property"},
584         {21,"no-vt-sessions-available"},
585         {22,"property-is-not-a-list"},
586         {23,"object-deletion-not-permitted"},
587         {24,"object-identifier-already-exists"},
588         {25,"operational-problem"},
589         {26,"password-failure"},
590         {27,"read-access-denied"},
591         {28,"security-not-supported"},
592         {29,"service-request-denied"},
593         {30,"timeout"},
594         {31,"unknown-object"},
595         {32,"unknown-property"},
596         {33,"removed enumeration"},
597         {34,"unknown-vt-class"},
598         {35,"unknown-vt-session"},
599         {36,"unsupported-object-type"},
600         {37,"value-out-of-range"},
601         {38,"vt-session-already-closed"},
602         {39,"vt-session-termination-failure"},
603         {40,"write-access-denied"},
604         {41,"character-set-not-supported"},
605         {42,"invalid-array-index"},
606         {43,"cov-subscription-failed"},
607         {44,"not-cov-property"},
608         {45,"optional-functionaltity-not-supported"},
609         {46,"invalid-configuration-data"},
610         {47,"datatype-not-supported"},
611         {48,"duplicate-name"},
612         {49,"duplicate-object-id"},
613         {50,"property-is-not-an-array"},
614         {0, NULL}
615 /* Enumerated values 0-255 are reserved for definition by ASHRAE. 
616    Enumerated values 256-65535 may be used by others subject to the 
617    procedures and constraints described in Clause 23. */
618 };
619
620 static const value_string
621 BACnetPropertyIdentifier [] = {
622         {0,"acked-transition"},
623         {1,"ack-required"},
624         {2,"action"},
625         {3,"action-text"},
626         {4,"active-text"},
627         {5,"active-vt-session"},
628         {6,"alarm-value"},
629         {7,"alarm-values"},
630         {8,"all"},
631         {9,"all-write-successful"},
632         {10,"apdu-segment-timeout"},
633         {11,"apdu-timeout"},
634         {12,"application-software-version"},
635         {13,"archive"},
636         {14,"bias"},
637         {15,"change-of-state-count"},
638         {16,"change-of-state-time"},
639         {17,"notification-class"},
640         {18,"the property in this place was deleted"},
641         {19,"controlled-variable-reference"},
642         {20,"controlled-variable-units"},
643         {21,"controlled-variable-value"},
644         {22,"cov-increment"},
645         {23,"datelist"},
646         {24,"daylights-savings-status"},
647         {25,"deadband"},
648         {26,"derivative-constant"},
649         {27,"derivative-constant-units"},
650         {28,"description"},
651         {29,"description-of-halt"},
652         {30,"device-address-binding"},
653         {31,"device-type"},
654         {32,"effective-period"},
655         {33,"elapsed-active-time"},
656         {34,"error-limit"},
657         {35,"event-enable"},
658         {36,"event-state"},
659         {37,"event-type"},
660         {38,"exception-schedule"},
661         {39,"fault-values"},
662         {40,"feedback-value"},
663         {41,"file-access-method"},
664         {42,"file-size"},
665         {43,"file-type"},
666         {44,"firmware-revision"},
667         {45,"high-limit"},
668         {46,"inactive-text"},
669         {47,"in-progress"},
670         {48,"instance-of"},
671         {49,"integral-constant"},
672         {50,"integral-constant-units"},
673         {51,"issue-confirmed-notifications"},
674         {52,"limit-enable"},
675         {53,"list-of-group-members"},
676         {54,"list-of-object-property-references"},
677         {55,"list-of-session-keys"},
678         {56,"local-date"},
679         {57,"local-time"},
680         {58,"location"},
681         {59,"low-limit"},
682         {60,"manipulated-variable-reference"},
683         {61,"maximum-output"},
684         {62,"max-apdu-length-accepted"},
685         {63,"max-info-frames"},
686         {64,"max-master"},
687         {65,"max-pres-value"},
688         {66,"minimum-off-time"},
689         {67,"minimum-on-time"},
690         {68,"minimum-output"},
691         {69,"min-pres-value"},
692         {70,"model-name"},
693         {71,"modification-date"},
694         {72,"notify-type"},
695         {73,"number-of-APDU-retries"},
696         {74,"number-of-states"},
697         {75,"object-identifier"},
698         {76,"object-list"},
699         {77,"object-name"},
700         {78,"object-property-reference"},
701         {79,"object-type"},
702         {80,"optional"},
703         {81,"out-of-service"},
704         {82,"output-units"},
705         {83,"event-parameters"},
706         {84,"polarity"},
707         {85,"present-value"},
708         {86,"priority"},
709         {87,"priority-array"},
710         {88,"priority-for-writing"},
711         {89,"process-identifier"},
712         {90,"program-change"},
713         {91,"program-location"},
714         {92,"program-state"},
715         {93,"proportional-constant"},
716         {94,"proportional-constant-units"},
717         {95,"protocol-conformance-class"},
718         {96,"protocol-object-types-supported"},
719         {97,"protocol-services-supported"},
720         {98,"protocol-version"},
721         {99,"read-only"},
722         {100,"reason-for-halt"},
723         {101,"recipient"},
724         {102,"recipient-list"},
725         {103,"reliability"},
726         {104,"relinquish-default"},
727         {105,"required"},
728         {106,"resolution"},
729         {107,"segmentation-supported"},
730         {108,"setpoint"},
731         {109,"setpoint-reference"},
732         {110,"state-text"},
733         {111,"status-flags"},
734         {112,"system-status"},
735         {113,"time-delay"},
736         {114,"time-of-active-time-reset"},
737         {115,"time-of-state-count-reset"},
738         {116,"time-synchronization-recipients"},
739         {117,"units"},
740         {118,"update-interval"},
741         {119,"utc-offset"},
742         {120,"vendor-identifier"},
743         {121,"vendor-name"},
744         {122,"vt-class-supported"},
745         {123,"weekly-schedule"},
746         {124,"attempted-samples"},
747         {125,"average-value"},
748         {126,"buffer-size"},
749         {127,"client-cov-increment"},
750         {128,"cov-resubscription-interval"},
751         {129,"current-notify-time"},
752         {130,"event-time-stamp"},
753         {131,"log-buffer"},
754         {132,"log-device-object-property"},
755         {133,"log-enable"},
756         {134,"log-interval"},
757         {135,"maximum-value"},
758         {136,"minimum-value"},
759         {137,"notification-threshold"},
760         {138,"previous-notify-time"},
761         {139,"protocol-revision"},
762         {140,"records-since-notification"},
763         {141,"record-count"},
764         {142,"start-time"},
765         {143,"stop-time"},
766         {144,"stop-when-full"},
767         {145,"total-record-count"},
768         {146,"valid-samples"},
769         {147,"window-interval"},
770         {148,"window-samples"},
771         {149,"maximum-value-time-stamp"},
772         {150,"minimum-value-time-stamp"},
773         {151,"variance-value"},
774         {152,"active-cov-subscriptions"},
775         {153,"backup-failure-timeout"},
776         {154,"configuration-files"},
777         {155,"database-revision"},
778         {156,"direct-reading"},
779         {157,"last-restore-time"},
780         {158,"maintenance-required"},
781         {159,"member-of"},
782         {160,"mode"},
783         {161,"operation-expected"},
784         {162,"setting"},
785         {163,"silenced"},
786         {164,"tracking-value"},
787         {165,"zone-members"},
788         {166,"life-safety-alarm-values"},
789         {167,"max-segments-accepted"},
790         {168,"profile-name"},
791         {169,"auto-slave-discovery"},
792         {170,"manual-slave-address-binding"},
793         {171,"slave-address-binding"},
794         {172,"slave-proxy-enable"},
795         {173,"last-notify-time"},
796         {174,"schedule-default"},
797         {175,"accepted-modes"},
798         {176,"adjust-value"},
799         {177,"count"},
800         {178,"count-before-change"},
801         {179,"count-change-time"},
802         {180,"cov-period"},
803         {181,"input-reference"},
804         {182,"limit-monitoring-interval"},
805         {183,"logging-device"},
806         {184,"logging-record"},
807         {185,"prescale"},
808         {186,"pulse-rate"},
809         {187,"scale"},
810         {188,"scale-factor"},
811         {189,"update-time"},
812         {190,"value-before-change"},
813         {191,"value-set"},
814         {192,"value-change-time"},
815         {0, NULL}
816 /* Enumerated values 0-511 are reserved for definition by ASHRAE. 
817    Enumerated values 512-4194303 may be used by others subject to 
818    the procedures and constraints described in Clause 23. */
819 };
820
821 static const value_string
822 BACnetBinaryPV [] = {
823         {0,"inactive"},
824         {1,"active"},
825         {0,NULL}
826 };
827
828
829 static const value_string
830 BACnetCharacterSet [] = {
831         {0,"ANSI X3.4"},
832         {1,"IBM/Microsoft DBCS"},
833         {2,"JIS C 6226"},
834         {3,"ISO 10646(UCS-4)"},
835         {4,"ISO 10646(UCS-2)"},
836         {5,"ISO 18859-1"},
837         {0,NULL}
838 };
839
840 static const value_string
841 BACnetStatusFlags [] = {
842         {0,"in-alarm"},
843         {1,"fault"},
844         {2,"overridden"},
845         {3,"out-of-service"},
846         {0,NULL}
847 };
848
849 static const value_string
850 BACnetMessagePriority [] = {
851         {0,"normal"},
852         {1,"urgent"},
853         {0,NULL}
854 };
855
856 static const value_string
857 BACnetAcknowledgementFilter [] = {
858         {0,"all"},
859         {1,"acked"},
860         {2,"not-acked"},
861         {0,NULL}
862 };
863
864 static const value_string
865 BACnetResultFlags [] = {
866         {0,"firstitem"},
867         {1,"lastitem"},
868         {2,"moreitems"},
869         {0,NULL}
870 };
871
872 static const value_string
873 BACnetRelationSpecifier [] = {
874         {0,"equal"},
875         {1,"not-equal"},
876         {2,"less-than"},
877         {3,"greater-than"},
878         {4,"less-than-or-equal"},
879         {5,"greater-than-or-equal"},
880         {0,NULL}
881 };
882
883 static const value_string
884 BACnetSelectionLogic [] = {
885         {0,"and"},
886         {1,"or"},
887         {2,"all"},
888         {0,NULL}
889 };
890
891 static const value_string
892 BACnetEventStateFilter [] = {
893         {0,"offnormal"},
894         {1,"fault"},
895         {2,"normal"},
896         {3,"all"},
897         {4,"active"},
898         {0,NULL}
899 };
900
901 static const value_string
902 BACnetEventTransitionBits [] = {
903         {0,"to-offnormal"},
904         {1,"to-fault"},
905         {2,"to-normal"},
906         {0,NULL}
907 };
908
909 static const value_string
910 BACnetSegmentation [] = {
911         {0,"segmented-both"},
912         {1,"segmented-transmit"},
913         {2,"segmented-receive"},
914         {3,"no-segmentation"},
915         {0,NULL}
916 };
917
918 static const value_string
919 BACnetSilencedState [] = {
920         {0,"unsilenced"},
921         {1,"audible-silenced"},
922         {2,"visible-silenced"},
923         {3,"all-silenced"},
924         {0,NULL}
925 };
926
927 static const value_string
928 BACnetDeviceStatus [] = {
929         {0,"operational"},
930         {1,"operational-read-only"},
931         {2,"download-required"},
932         {3,"download-in-progress"},
933         {4,"non-operational"},
934         {5,"backup-in-progress"},
935         {0,NULL}
936 };
937
938 static const value_string
939 BACnetEnableDisable [] = {
940         {0,"enable"},
941         {1,"disable"},
942         {2,"disable-initiation"},
943         {0,NULL}
944 };
945
946 static const value_string
947 months [] = {
948         {1,"January" },
949         {2,"February" },
950         {3,"March" },
951         {4,"April" },
952         {5,"May" },
953         {6,"June" },
954         {7,"July" },
955         {8,"August" },
956         {9,"September" },
957         {10,"October" },
958         {11,"November" },
959         {12,"December" },
960         {255,"any month" },
961         {0,NULL }
962 };
963
964 static const value_string
965 weekofmonth [] = {
966         {1,"days numbered 1-7" },
967         {2,"days numbered 8-14" },
968         {3,"days numbered 15-21" },
969         {4,"days numbered 22-28" },
970         {5,"days numbered 29-31" },
971         {6,"last 7 days of this month" },
972         {255,"any week of this month" },
973         {0,NULL }
974 };
975
976 static const value_string
977 days [] = {
978         {1,"Monday" },
979         {2,"Tuesday" },
980         {3,"Wednesday" },
981         {4,"Thursday" },
982         {5,"Friday" },
983         {6,"Saturday" },
984         {7,"Sunday" },
985         {255,"any day of week" },
986         {0,NULL },
987 };
988
989 static const value_string
990 BACnetErrorClass [] = {
991         {0,"device" },
992         {1,"object" },
993         {2,"property" },
994         {3,"resources" },
995         {4,"security" },
996         {5,"services" },
997         {6,"vt" },
998         {0,NULL },
999 /* Enumerated values 0-63 are reserved for definition by ASHRAE. 
1000    Enumerated values64-65535 may be used by others subject to 
1001    the procedures and constraints described in Clause 23. */
1002 };
1003
1004 static const value_string
1005 BACnetVTClass [] = {
1006         {0,"default-terminal" },
1007         {1,"ansi-x3-64" },
1008         {2,"dec-vt52" },
1009         {3,"dec-vt100" },
1010         {4,"dec-vt200" },
1011         {5,"hp-700-94" },
1012         {6,"ibm-3130" },
1013         {0,NULL },
1014 };
1015
1016 static const value_string
1017 BACnetEventType [] = {
1018         {0,"change-of-bitstring" },
1019         {1,"change-of-state" },
1020         {2,"change-of-value" },
1021         {3,"command-failure" },
1022         {4,"floating-limit" },
1023         {5,"out-of-range" },
1024         {6,"complex-event-type" },
1025         {7,"buffer-ready" },
1026         {8,"change-of-life-safety" },
1027         {9,"extended" },
1028         {10,"buffer-ready" },
1029         {11,"unsigned-range" },
1030         {0,NULL },
1031 /* Enumerated values 0-63 are reserved for definition by ASHRAE. 
1032    Enumerated values 64-65535 may be used by others subject to 
1033    the procedures and constraints described in Clause 23. 
1034    It is expected that these enumerated values will correspond 
1035    to the use of the complex-event-type CHOICE [6] of the 
1036    BACnetNotificationParameters production. */
1037 };
1038
1039 static const value_string
1040 BACnetEventState [] = {
1041         {0,"normal" },
1042         {1,"fault" },
1043         {2,"offnormal" },
1044         {3,"high-limit" },
1045         {4,"low-limit" },
1046         {5,"life-safety-alarm" },
1047         {0,NULL },
1048 /* Enumerated values 0-63 are reserved for definition by ASHRAE. 
1049    Enumerated values 64-65535 may be used by others subject to 
1050    the procedures and constraints described in Clause 23.  */
1051 };
1052
1053 static const value_string
1054 BACnetLogStatus [] = {
1055         {0,"log-disabled" },
1056         {1,"buffer-purged" },
1057         {0,NULL },
1058 };
1059
1060 static const value_string
1061 BACnetMaintenance [] = {
1062         {0,"none" },
1063         {1,"periodic-test" },
1064         {2,"need-service-operational" },
1065         {3,"need-service-inoperative" },
1066         {0,NULL },
1067 };
1068
1069 static const value_string
1070 BACnetNotifyType [] = {
1071         {0,"alarm" },
1072         {1,"event" },
1073         {2,"ack-notification" },
1074         {0,NULL },
1075 };
1076
1077 static const value_string
1078 BACnetServicesSupported [] = {
1079         {0,"acknowledgeAlarm"},
1080         {1,"confirmedCOVNotification"},
1081         {2,"confirmedEventNotification"},
1082         {3,"getAlarmSummary"},
1083         {4,"getEnrollmentSummary"},
1084         {5,"subscribeCOV"},
1085         {6,"atomicReadFile"},
1086         {7,"atomicWriteFile"},
1087         {8,"addListElement"},
1088         {9,"removeListElement"},
1089         {10,"createObject"},
1090         {11,"deleteObject"},
1091         {12,"readProperty"},
1092         {13,"readPropertyConditional"},
1093         {14,"readPropertyMultiple"},
1094         {15,"writeProperty"},
1095         {16,"writePropertyMultiple"},
1096         {17,"deviceCommunicationControl"},
1097         {18,"confirmedPrivateTransfer"},
1098         {19,"confirmedTextMessage"},
1099         {20,"reinitializeDevice"},
1100         {21,"vtOpen"},
1101         {22,"vtClose"},
1102         {23,"vtData"},
1103         {24,"authenticate"},
1104         {25,"requestKey"},
1105         {26,"i-Am"},
1106         {27,"i-Have"},
1107         {28,"unconfirmedCOVNotification"},
1108         {29,"unconfirmedEventNotification"},
1109         {30,"unconfirmedPrivateTransfer"},
1110         {31,"unconfirmedTextMessage"},
1111         {32,"timeSynchronization"},
1112         {33,"who-Has"},
1113         {34,"who-Is"},
1114         {35,"readRange"},
1115         {36,"utcTimeSynchronization"},
1116         {37,"lifeSafetyOperation"},
1117         {38,"subscribeCOVProperty"},
1118         {39,"getEventInformation"},
1119         {0, NULL}
1120 };
1121
1122 static const value_string
1123 BACnetPropertyStates [] = {
1124         {0,"boolean-value"},
1125         {1,"binary-value"},
1126         {2,"event-type"},
1127         {3,"polarity"},
1128         {4,"program-change"},
1129         {5,"program-state"},
1130         {6,"reason-for-halt"},
1131         {7,"reliability"},
1132         {8,"state"},
1133         {9,"system-status"},
1134         {10,"units"},
1135         {11,"unsigned-value"},
1136         {12,"life-safety-mode"},
1137         {13,"life-safety-state"},
1138         {0,NULL}
1139 /* Tag values 0-63 are reserved for definition by ASHRAE. 
1140    Tag values of 64-254 may be used by others to accommodate 
1141    vendor specific properties that have discrete or enumerated values, 
1142    subject to the constraints described in Clause 23. */
1143 };
1144
1145 static const value_string
1146 BACnetProgramError [] = {
1147         {0,"normal"},
1148         {1,"load-failed"},
1149         {2,"internal"},
1150         {3,"program"},
1151         {4,"other"},
1152         {0,NULL}
1153 /* Enumerated values 0-63 are reserved for definition by ASHRAE. 
1154    Enumerated values 64-65535 may be used by others subject to 
1155    the procedures and constraints described in Clause 23. */
1156 };
1157
1158 static const value_string
1159 BACnetProgramRequest [] = {
1160         {0,"ready"},
1161         {1,"load"},
1162         {2,"run"},
1163         {3,"halt"},
1164         {4,"restart"},
1165         {4,"unload"},
1166         {0,NULL}
1167 };
1168
1169 static const value_string
1170 BACnetProgramState [] = {
1171         {0,"idle"},
1172         {1,"loading"},
1173         {2,"running"},
1174         {3,"waiting"},
1175         {4,"halted"},
1176         {4,"unloading"},
1177         {0,NULL}
1178 };
1179
1180 static const value_string
1181 BACnetReinitializedStateOfDevice [] = {
1182         {0,"coldstart"},
1183         {1,"warmstart"},
1184         {2,"startbackup"},
1185         {3,"endbackup"},
1186         {4,"startrestore"},
1187         {5,"endrestore"},
1188         {6,"abortrestore"},
1189         {0,NULL}
1190 };
1191
1192 static const value_string
1193 BACnetPolarity [] = {
1194         {0,"normal"},
1195         {1,"reverse"},
1196         {0,NULL}
1197 };
1198
1199 static const value_string
1200 BACnetTagNames[] = {
1201         { 5, "Extended Value" },
1202         { 6, "Opening Tag" },
1203         { 7, "Closing Tag" },
1204         { 0, NULL }
1205 };
1206
1207 static int proto_bacapp = -1;
1208 static int hf_bacapp_type = -1;
1209 static int hf_bacapp_pduflags = -1;
1210 static int hf_bacapp_SEG = -1;
1211 static int hf_bacapp_MOR = -1;
1212 static int hf_bacapp_SA = -1;
1213 static int hf_bacapp_response_segments = -1;
1214 static int hf_bacapp_max_adpu_size = -1;
1215 static int hf_bacapp_invoke_id = -1;
1216 static int hf_bacapp_objectType = -1;
1217 static int hf_bacapp_instanceNumber = -1;
1218 static int hf_bacapp_sequence_number = -1;
1219 static int hf_bacapp_window_size = -1;
1220 static int hf_bacapp_service = -1;
1221 static int hf_bacapp_NAK = -1;
1222 static int hf_bacapp_SRV = -1;
1223 static int hf_BACnetRejectReason = -1;
1224 static int hf_BACnetAbortReason = -1;
1225 static int hf_BACnetApplicationTagNumber = -1;
1226 static int hf_BACnetContextTagNumber = -1;
1227 static int hf_BACnetExtendedTagNumber = -1;
1228 static int hf_BACnetNamedTag = -1;
1229 static int hf_BACnetTagClass = -1;
1230 static int hf_BACnetCharacterSet = -1;
1231 static int hf_bacapp_tag = -1;
1232 static int hf_bacapp_tag_lvt = -1;
1233 static int hf_bacapp_tag_value8 = -1;
1234 static int hf_bacapp_tag_value16 = -1;
1235 static int hf_bacapp_tag_value32 = -1;
1236 static int hf_bacapp_tag_ProcessId = -1;
1237 static int hf_bacapp_tag_initiatingObjectType = -1;
1238 static int hf_bacapp_vpart = -1;
1239
1240 static int hf_bacapp_uservice = -1;
1241
1242
1243 static gint ett_bacapp = -1;
1244 static gint ett_bacapp_control = -1;
1245 static gint ett_bacapp_tag = -1;
1246 static gint ett_bacapp_list = -1;
1247 static gint ett_bacapp_value = -1;
1248
1249 static dissector_handle_t data_handle;
1250 static gint32 propertyIdentifier = -1;
1251 static guint32 object_type = 4096;
1252
1253 static guint8 bacapp_flags = 0;
1254 static guint8 bacapp_seq = 0;
1255
1256 /* Used when there are ranges of reserved and proprietary enumerations */
1257 static const char*
1258 val_to_split_str(guint32 val, guint32 split_val, const value_string *vs,
1259         const char *fmt, const char *split_fmt)
1260 {
1261         if (val < split_val)
1262                 return val_to_str(val, vs, fmt);
1263         else
1264                 return val_to_str(val, vs, split_fmt);
1265 }
1266
1267 /* from clause 20.2.1.3.2 Constructed Data */
1268 /* returns true if the extended value is used */
1269 static gboolean tag_is_extended_value(guint8 tag)
1270 {
1271         return (tag & 0x07) == 5;
1272 }
1273
1274 static gboolean tag_is_opening(guint8 tag)
1275 {
1276         return (tag & 0x07) == 6;
1277 }
1278
1279 static gboolean tag_is_closing(guint8 tag)
1280 {
1281         return (tag & 0x07) == 7;
1282 }
1283
1284 /* from clause 20.2.1.1 Class
1285    class bit shall be one for context specific tags */
1286 /* returns true if the tag is context specific */
1287 static gboolean tag_is_context_specific(guint8 tag)
1288 {
1289         return (tag & 0x08) != 0;
1290 }
1291
1292 static gboolean tag_is_extended_tag_number(guint8 tag)
1293 {
1294         return ((tag & 0xF0) == 0xF0);
1295 }
1296
1297 static guint32 object_id_type(guint32 object_identifier)
1298 {
1299         return ((object_identifier >> 22) & 0x3FF);
1300 }
1301
1302 static guint32 object_id_instance(guint32 object_identifier)
1303 {
1304         return (object_identifier & 0x3FFFFF);
1305 }
1306
1307 static guint
1308 fTagNo (tvbuff_t *tvb, guint offset)
1309 {
1310         return (guint)(tvb_get_guint8(tvb, offset) >> 4);
1311 }
1312
1313 static gboolean
1314 fUnsigned32 (tvbuff_t *tvb, guint offset, guint32 lvt, guint32 *val)
1315 {
1316         gboolean valid = TRUE;
1317         
1318         switch (lvt) {
1319                 case 1:
1320                         *val = tvb_get_guint8(tvb, offset);
1321                         break;
1322                 case 2:
1323                         *val = tvb_get_ntohs(tvb, offset);
1324                         break;
1325                 case 3:
1326                         *val = tvb_get_ntoh24(tvb, offset);
1327                         break;
1328                 case 4:
1329                         *val = tvb_get_ntohl(tvb, offset);
1330                         break;
1331                 default:
1332                         valid = FALSE;
1333                         break;
1334         }
1335         
1336         return valid;
1337 }
1338
1339 static gboolean
1340 fUnsigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, guint64 *val)
1341 {
1342         gboolean valid = TRUE;
1343         
1344         switch (lvt) {
1345                 case 1:
1346                         *val = tvb_get_guint8(tvb, offset);
1347                         break;
1348                 case 2:
1349                         *val = tvb_get_ntohs(tvb, offset);
1350                         break;
1351                 case 3:
1352                         *val = tvb_get_ntoh24(tvb, offset);
1353                         break;
1354                 case 4:
1355                         *val = tvb_get_ntohl(tvb, offset);
1356                         break;
1357                 case 8:
1358                         *val = tvb_get_ntoh64(tvb, offset);
1359                         break;
1360                 default:
1361                         valid = FALSE;
1362                         break;
1363         }
1364         
1365         return valid;
1366 }
1367
1368 static guint
1369 fTagHeaderTree (tvbuff_t *tvb, proto_tree *tree, guint offset,
1370         guint8 *tag_no, guint8* tag_info, guint32 *lvt)
1371 {
1372         guint8 tag;
1373         guint8 value;
1374         guint tag_len = 1;
1375         guint lvt_len = 1; /* used for tree display of lvt */
1376         guint lvt_offset; /* used for tree display of lvt */
1377         proto_item *ti;
1378         proto_tree *subtree;
1379
1380         lvt_offset = offset;
1381         tag = tvb_get_guint8(tvb, offset);
1382         *tag_info = 0;
1383         *lvt = tag & 0x07;
1384     /* To solve the problem of lvt values of 6/7 being indeterminate - it */
1385     /* can mean open/close tag or length of 6/7 after the length is */
1386     /* computed below - store whole tag info, not just context bit. */
1387         if (tag_is_context_specific(tag)) *tag_info = tag & 0x0F;
1388         *tag_no = tag >> 4;
1389         if (tag_is_extended_tag_number(tag)) { 
1390                 *tag_no = tvb_get_guint8(tvb, offset + tag_len++);
1391         }
1392         if (tag_is_extended_value(tag)) {       /* length is more than 4 Bytes */
1393                 lvt_offset += tag_len;
1394                 value = tvb_get_guint8(tvb, lvt_offset);
1395                 tag_len++;
1396                 if (value == 254) { /* length is encoded with 16 Bits */
1397                         *lvt = tvb_get_ntohs(tvb, lvt_offset+1);
1398                         tag_len += 2;
1399                         lvt_len += 2;
1400                 } else if (value == 255) { /* length is encoded with 32 Bits */
1401                         *lvt = tvb_get_ntohl(tvb, lvt_offset+1);
1402                         tag_len += 4;
1403                         lvt_len += 4;
1404                 } else
1405                         *lvt = value;
1406         }
1407         if (tree)
1408         {
1409                 if (tag_is_closing(tag) || tag_is_opening(tag))
1410                         ti = proto_tree_add_text(tree, tvb, offset, tag_len,
1411                                 "%s: %u", match_strval(
1412                                         tag & 0x07, BACnetTagNames),
1413                                 *tag_no);
1414                 else if (tag_is_context_specific(tag)) {
1415                         ti = proto_tree_add_text(tree, tvb, offset, tag_len,
1416                                 "Context Tag: %u, Length/Value/Type: %u",
1417                                 *tag_no, *lvt);
1418                 } else
1419                         ti = proto_tree_add_text(tree, tvb, offset, tag_len,
1420                                 "Application Tag: %s, Length/Value/Type: %u",
1421                                 val_to_str(*tag_no,
1422                                         BACnetApplicationTagNumber,
1423                                         ASHRAE_Reserved_Fmt),
1424                                         *lvt);
1425                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1426                 /* details if needed */
1427                 proto_tree_add_item(subtree, hf_BACnetTagClass, tvb, offset, 1, FALSE);
1428                 if (tag_is_extended_tag_number(tag)) {
1429                         proto_tree_add_uint_format(subtree,
1430                                         hf_BACnetContextTagNumber,
1431                                         tvb, offset, 1, tag,
1432                                         "Extended Tag Number");
1433                         proto_tree_add_item(subtree,
1434                                 hf_BACnetExtendedTagNumber,
1435                                 tvb, offset + 1, 1, FALSE);
1436                 } else {
1437                         if (tag_is_context_specific(tag))
1438                                 proto_tree_add_item(subtree,
1439                                         hf_BACnetContextTagNumber,
1440                                         tvb, offset, 1, FALSE);
1441                         else
1442                                 proto_tree_add_item(subtree,
1443                                         hf_BACnetApplicationTagNumber,
1444                                         tvb, offset, 1, FALSE);
1445                 }
1446                 if (tag_is_closing(tag) || tag_is_opening(tag))
1447                         proto_tree_add_item(subtree,
1448                                 hf_BACnetNamedTag,
1449                                 tvb, offset, 1, FALSE);
1450                 else if (tag_is_extended_value(tag)) {
1451                         proto_tree_add_item(subtree,
1452                                 hf_BACnetNamedTag,
1453                                 tvb, offset, 1, FALSE);
1454                         proto_tree_add_uint(subtree, hf_bacapp_tag_lvt,
1455                                 tvb, lvt_offset, lvt_len, *lvt);
1456                 } else
1457                         proto_tree_add_uint(subtree, hf_bacapp_tag_lvt,
1458                                 tvb, lvt_offset, lvt_len, *lvt);
1459         }
1460   
1461         return tag_len;
1462 }
1463
1464 static guint
1465 fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* tag_info,
1466         guint32 *lvt)
1467 {
1468         return fTagHeaderTree (tvb, NULL, offset, tag_no, tag_info, lvt);
1469 }
1470
1471 static guint
1472 fNullTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1473 {
1474         guint8 tag_no, tag_info;
1475         guint32 lvt;
1476         proto_item *ti;
1477         proto_tree *subtree;
1478
1479         ti = proto_tree_add_text(tree, tvb, offset, 1, "%sNULL", label);
1480         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1481         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1482
1483         return offset + 1;
1484 }
1485
1486 static guint
1487 fBooleanTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1488 {
1489         guint8 tag_no, tag_info;
1490         guint32 lvt = 0;
1491         guint tag_len;
1492         proto_item *ti;
1493         proto_tree *subtree;
1494         guint bool_len = 1;
1495
1496         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1497         if (tag_info && lvt == 1)
1498         {
1499                 lvt = tvb_get_guint8(tvb, offset+1);
1500                 ++bool_len;
1501         }
1502
1503         ti = proto_tree_add_text(tree, tvb, offset, bool_len,
1504                 "%s%s", label, lvt == 0 ? "FALSE" : "TRUE");
1505         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1506         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1507
1508         return offset + bool_len;
1509 }
1510
1511 static guint
1512 fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1513 {
1514         guint64 val = 0;
1515         guint8 tag_no, tag_info;
1516         guint32 lvt;
1517     guint tag_len;
1518         proto_item *ti;
1519         proto_tree *subtree;
1520
1521         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1522         /* only support up to an 8 byte (64-bit) integer */
1523         if (fUnsigned64 (tvb, offset + tag_len, lvt, &val))
1524                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1525                         "%s(Unsigned) %" PRIu64, label, val);
1526         else
1527                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1528                         "%s - %u octets (Unsigned)", label, lvt);
1529         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1530         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1531         
1532         return offset+tag_len+lvt;
1533 }
1534
1535 /* set split_val to zero when not needed */
1536 static guint
1537 fEnumeratedTagSplit (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
1538         const value_string *vs, guint32 split_val)
1539 {
1540         guint32 val = 0;
1541         guint8 tag_no, tag_info;
1542         guint32 lvt;
1543         guint tag_len;
1544         proto_item *ti;
1545         proto_tree *subtree;
1546
1547         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1548         /* only support up to a 4 byte (32-bit) enumeration */
1549         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val)) {
1550                 if (vs)
1551                         ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1552                                 "%s %s", label, val_to_split_str(val, split_val, vs,    
1553                                 ASHRAE_Reserved_Fmt,Vendor_Proprietary_Fmt));
1554                 else
1555                         ti =proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1556                                 "%s %u", label, val);
1557         } else {
1558                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1559                         "%s - %u octets (enumeration)", label, lvt);
1560         }
1561         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1562         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1563
1564         return offset+tag_len+lvt;
1565 }
1566
1567 static guint
1568 fEnumeratedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
1569         const value_string *vs)
1570 {
1571         return fEnumeratedTagSplit (tvb, tree, offset, label, vs, 0);
1572 }
1573
1574 static guint
1575 fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1576 {
1577         guint64 val = 0;
1578         guint8 tag_no, tag_info;
1579         guint32 lvt;
1580         guint tag_len;
1581         proto_item *ti;
1582         proto_tree *subtree;
1583
1584         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1585         if (fUnsigned64 (tvb, offset + tag_len, lvt, &val))
1586                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1587                         "%s(Signed) %" PRId64, label, (gint64) val);
1588         else
1589                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1590                         "%s - %u octets (Signed)", label, lvt);
1591         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1592         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1593         
1594         return offset+tag_len+lvt;
1595 }
1596
1597 static guint
1598 fRealTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1599 {
1600         guint8 tag_no, tag_info;
1601         guint32 lvt;
1602         guint tag_len;
1603         gfloat f_val = 0.0;
1604         proto_item *ti;
1605         proto_tree *subtree;
1606         
1607         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
1608         f_val = tvb_get_ntohieee_float(tvb, offset+tag_len);
1609         ti = proto_tree_add_text(tree, tvb, offset, 4+tag_len,
1610                 "%s%f (Real)", label, f_val);
1611         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1612         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1613         
1614         return offset+tag_len+4;
1615 }
1616
1617 static guint
1618 fDoubleTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1619 {
1620         guint8 tag_no, tag_info;
1621         guint32 lvt;
1622         guint tag_len;
1623         gdouble d_val = 0.0;
1624         proto_item *ti;
1625         proto_tree *subtree;
1626         
1627         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
1628         d_val = tvb_get_ntohieee_double(tvb, offset+tag_len);
1629         ti = proto_tree_add_text(tree, tvb, offset, 8+tag_len,
1630                 "%s%lf (Double)", label, d_val);
1631         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1632         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1633         
1634         return offset+tag_len+8;
1635 }
1636
1637 static guint
1638 fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset)
1639 {
1640         guint32 val = 0, lvt;
1641         guint8 tag_no, tag_info;
1642         proto_item *ti;
1643         proto_tree *subtree;
1644         guint tag_len;
1645
1646         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1647         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val))
1648                 ti = proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId, 
1649                         tvb, offset, lvt+tag_len, val);
1650         else
1651                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1652                         "Process Identifier - %u octets (Signed)", lvt);
1653         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1654         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1655         
1656         return offset+tag_len+lvt;
1657 }
1658
1659 static guint
1660 fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1661 {
1662         guint32 val = 0, lvt;
1663         guint8 tag_no, tag_info;
1664         proto_item *ti;
1665         proto_tree *subtree;
1666         guint tag_len;
1667
1668         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1669         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val))
1670                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, 
1671                 "%s (hh.mm.ss): %d.%02d.%02d%s", 
1672                 label, 
1673                 (val / 3600), ((val % 3600) / 60), (val % 60), 
1674                 val == 0 ? " (indefinite)" : "");
1675         else
1676                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1677                         "%s - %u octets (Signed)", label, lvt);
1678         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1679         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1680
1681         return offset+tag_len+lvt;
1682 }
1683
1684 static guint
1685 fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset)
1686 {
1687         guint32 month, weekOfMonth, dayOfWeek;
1688         guint8 tag_no, tag_info;
1689         guint32 lvt;
1690         guint tag_len;
1691         proto_item *ti;
1692         proto_tree *subtree;
1693
1694         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1695         month = tvb_get_guint8(tvb, offset+tag_len);
1696         weekOfMonth = tvb_get_guint8(tvb, offset+tag_len+1);
1697         dayOfWeek = tvb_get_guint8(tvb, offset+tag_len+2);
1698         ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s %s, %s", 
1699                         val_to_str(month, months, "month (%d) not found"), 
1700                         val_to_str(weekOfMonth, weekofmonth, "week of month (%d) not found"), 
1701                         val_to_str(dayOfWeek, days, "day of week (%d) not found"));
1702         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1703         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1704
1705         return offset+tag_len+lvt;
1706 }
1707
1708 static guint
1709 fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1710 {
1711         guint32 year, month, day, weekday;
1712         guint8 tag_no, tag_info;
1713         guint32 lvt;
1714         guint tag_len;
1715         proto_item *ti;
1716         proto_tree *subtree;
1717
1718         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1719         year = tvb_get_guint8(tvb, offset+tag_len);
1720         month = tvb_get_guint8(tvb, offset+tag_len+1);
1721         day = tvb_get_guint8(tvb, offset+tag_len+2);
1722         weekday = tvb_get_guint8(tvb, offset+tag_len+3);
1723         if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
1724         {
1725                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1726                         "%sany", label);
1727         }
1728         else if (year != 255)
1729         {
1730                 year += 1900;
1731                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1732                         "%s%s %d, %d, (Day of Week = %s)",
1733                         label, val_to_str(month,
1734                                 months,
1735                                 "month (%d) not found"),
1736                         day, year, val_to_str(weekday,
1737                                 days,
1738                                 "(%d) not found"));
1739         }
1740         else
1741         {
1742                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1743                         "%s%s %d, any year, (Day of Week = %s)",
1744                         label, val_to_str(month, months, "month (%d) not found"),
1745                         day, val_to_str(weekday, days, "(%d) not found"));
1746         }
1747         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1748         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1749
1750         return offset+tag_len+lvt;
1751 }
1752
1753 static guint
1754 fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1755 {
1756         guint32 hour, minute, second, msec, lvt;
1757         guint8 tag_no, tag_info;
1758         guint tag_len;
1759         proto_item *ti;
1760         proto_tree *subtree;
1761
1762         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1763         hour = tvb_get_guint8(tvb, offset+tag_len);
1764         minute = tvb_get_guint8(tvb, offset+tag_len+1);
1765         second = tvb_get_guint8(tvb, offset+tag_len+2);
1766         msec = tvb_get_guint8(tvb, offset+tag_len+3);
1767         if ((hour == 255) && (minute == 255) && (second == 255) && (msec == 255))
1768                 ti = proto_tree_add_text(tree, tvb, offset,
1769                         lvt+tag_len, "%sany", label);
1770         else
1771                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1772                         "%s%d:%02d:%02d.%d %s = %02d:%02d:%02d.%d",
1773                         label,
1774                         hour > 12 ? hour - 12 : hour,
1775                         minute, second, msec,
1776                         hour > 12 ? "P.M." : "A.M.",
1777                         hour, minute, second, msec);
1778         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1779         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1780         
1781         return offset+tag_len+lvt;
1782 }
1783
1784 static guint
1785 fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1786 {
1787         proto_tree *subtree = tree;
1788         proto_item *tt;
1789
1790         if (label != NULL) {
1791                 tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", label);
1792                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
1793         }
1794         offset = fDate (tvb,subtree,offset,"Date: ");
1795         return fTime (tvb,subtree,offset,"Time: ");
1796 }
1797
1798 static guint
1799 fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
1800 {
1801         guint lastoffset = 0;
1802         guint8 tag_no, tag_info;
1803         guint32 lvt;                               
1804
1805         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
1806                 lastoffset = offset;
1807                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1808                 if (tag_is_closing(tag_info)) {   /* closing Tag, but not for me */
1809                         return offset;
1810                 }
1811                 offset = fTime    (tvb,tree,offset,"Time: ");
1812                 offset = fApplicationTypes(tvb, tree, offset, "Value: ");
1813         }
1814         return offset;
1815 }
1816
1817 static guint
1818 fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset)
1819 {
1820     guint8 tag_no, tag_info;
1821     guint32 lvt;
1822
1823         switch (fTagNo(tvb, offset)) {
1824         case 0: /* Date */
1825                 offset = fDate    (tvb, tree, offset, "Date: ");
1826                 break;
1827         case 1: /* dateRange */
1828         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
1829                 offset = fDateRange (tvb, tree, offset);
1830         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
1831                 break;
1832         case 2: /* BACnetWeekNDay */
1833                 offset = fWeekNDay (tvb, tree, offset);
1834                 break;
1835         default:
1836                 return offset;
1837                 break;
1838         }
1839
1840         return offset;
1841 }
1842
1843 static guint
1844 fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset)
1845 {
1846         guint8 tag_no = 0, tag_info = 0;
1847         guint32 lvt = 0;
1848
1849         if (tvb_length_remaining(tvb, offset) > 0) {    /* don't loop, it's a CHOICE */
1850                 switch (fTagNo(tvb, offset)) {
1851                 case 0: /* time */
1852                         offset = fTime (tvb, tree, offset, "timestamp: ");
1853                         break;
1854                 case 1: /* sequenceNumber */
1855                         offset = fUnsignedTag (tvb, tree, offset, "sequence Number: ");
1856                         break;
1857                 case 2: /* dateTime */
1858                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
1859                         offset = fDateTime (tvb, tree, offset, "timestamp: ");
1860                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
1861                         break;
1862                 default:
1863                         return offset;
1864                         break;
1865                 }
1866         }
1867         return offset;
1868 }
1869
1870 #if 0
1871 static guint
1872 fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
1873 {
1874         guint lastoffset = 0;
1875
1876         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
1877                 lastoffset = offset;
1878         
1879                 switch (fTagNo(tvb, offset)) {
1880                 case 0: /* setpointReference */
1881                         offset = fBACnetObjectPropertyReference (tvb,tree,offset);
1882                         break;
1883                 default:
1884                         return offset;
1885                         break;
1886                 }
1887         }
1888         return offset;
1889 }
1890 #endif
1891
1892 #if 0
1893 static guint
1894 fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset)
1895 {
1896         if (tvb_length_remaining(tvb, offset) > 0) {
1897         offset = fApplicationTypes(tvb,tree,offset, "increment: ");
1898     }
1899     return offset;
1900 }
1901
1902 static guint
1903 fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset)
1904 {
1905         if (tvb_length_remaining(tvb, offset) > 0) {
1906                 offset = fApplicationTypesEnumerated(tvb,tree,offset, 
1907                         "valid Days: ", days);
1908                 offset = fTime (tvb,tree,offset,"from time: ");
1909                 offset = fTime (tvb,tree,offset,"to time: ");
1910                 offset = fRecipient (tvb,tree,offset);
1911                 offset = fProcessId (tvb,tree,offset);
1912                 offset = fApplicationTypes (tvb,tree,offset,
1913                         "issue confirmed notifications: ");
1914                 offset = fApplicationTypesEnumerated (tvb,tree,offset,
1915                         "transitions: ", BACnetEventTransitionBits);
1916         }
1917         return offset;
1918 }
1919
1920 #endif
1921
1922 static guint
1923 fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, guint32 lvt)
1924 {
1925         gchar *tmp;
1926     guint start = offset;
1927         guint8 tag_no, tag_info;
1928     proto_tree* subtree = tree;
1929     proto_item* ti = 0;
1930
1931         offset += fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1932
1933         if (lvt > 0)
1934     {
1935             tmp = tvb_bytes_to_str(tvb, offset, lvt);
1936             ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s %s", label, tmp);
1937                 offset += lvt;
1938     }
1939
1940         if (ti)
1941         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1942
1943     fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt);
1944
1945         return offset;
1946 }
1947
1948 static guint
1949 fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset)
1950 {
1951         guint8 tag_no, tag_info;
1952         guint32 lvt;
1953     guint offs;
1954
1955         offset = fUnsignedTag (tvb, tree, offset, "network-number");
1956         offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1957         if (lvt == 0) {
1958                 proto_tree_add_text(tree, tvb, offset, offs, "mac-address: broadcast");
1959                 offset += offs;
1960         } else
1961                 offset = fOctetString (tvb, tree, offset, "mac-address: ", lvt);
1962         return offset;
1963 }
1964
1965 #if 0
1966 static guint
1967 fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset)
1968 {
1969         offset = fOctetString (tvb,tree,offset,"session key: ", 8);
1970         return fAddress (tvb,tree,offset);
1971 }
1972 #endif
1973
1974 static guint
1975 fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
1976 {
1977         guint8  tag_no, tag_info;
1978         guint32 lvt;
1979         guint tag_length;
1980         proto_item *ti;
1981         proto_tree *subtree;
1982         guint32 object_id;
1983
1984         tag_length = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
1985         object_id = tvb_get_ntohl(tvb,offset+tag_length);
1986         object_type = object_id_type(object_id);
1987         ti = proto_tree_add_text(tree, tvb, offset, tag_length + 4,
1988                 "ObjectIdentifier: %s, %u",
1989                 val_to_split_str(object_type,
1990                         128,
1991                         BACnetObjectType,
1992                         ASHRAE_Reserved_Fmt,
1993                         Vendor_Proprietary_Fmt),
1994                 object_id_instance(object_id));
1995         /* here are the details of how we arrived at the above text */
1996         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1997         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1998         offset += tag_length;
1999         proto_tree_add_item(subtree, hf_bacapp_objectType, tvb, offset, 4, FALSE);
2000         proto_tree_add_item(subtree, hf_bacapp_instanceNumber, tvb, offset, 4, FALSE);
2001         offset += 4;
2002
2003         return offset;
2004 }
2005
2006 static guint
2007 fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset)
2008 {
2009         guint lastoffset = 0;
2010
2011         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2012                 lastoffset = offset;
2013         
2014                 switch (fTagNo(tvb, offset)) {
2015                 case 0: /* device */
2016                         offset = fObjectIdentifier (tvb, tree, offset);
2017                         break;
2018                 case 1: /* address */
2019                         offset = fAddress (tvb, tree, offset);
2020                         break;
2021                 default:
2022                         return offset;
2023                         break;
2024                 }
2025         }
2026         return offset;
2027 }
2028
2029 static guint
2030 fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset)
2031 {
2032         guint lastoffset = 0;
2033
2034         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2035                 lastoffset = offset;
2036         
2037                 switch (fTagNo(tvb, offset)) {
2038                 case 0: /* recipient */
2039                         offset = fRecipient (tvb, tree, offset);
2040                         break;
2041                 case 1: /* processId */
2042                         offset = fProcessId (tvb, tree, offset);
2043                         break;
2044                 default:
2045                         return offset;
2046                         break;
2047                 }
2048         }
2049         return offset;
2050 }
2051
2052 static guint
2053 fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset)
2054 {
2055         offset = fObjectIdentifier (tvb, tree, offset);
2056         return fAddress (tvb, tree, offset);
2057 }
2058
2059 static guint
2060 fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset)
2061 {
2062         guint lastoffset = 0;
2063         guint8 tag_no, tag_info;
2064         guint32 lvt;
2065         proto_tree *subtree = tree;
2066         proto_item *tt;
2067
2068         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2069                 lastoffset = offset;
2070                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2071                 if (tag_is_closing(tag_info)) {  
2072                         offset += fTagHeaderTree (tvb, subtree, offset,
2073                                 &tag_no, &tag_info, &lvt);
2074                         subtree = tree;
2075                         continue;
2076                 }
2077                 switch (tag_no) {
2078         
2079                 case 0: /* deviceIdentifier */
2080                         offset = fObjectIdentifier (tvb, subtree, offset);
2081                         break;
2082                 case 1: /* objectIdentifier */
2083                         offset = fObjectIdentifier (tvb, subtree, offset);
2084                         break;
2085                 case 2: /* propertyIdentifier */
2086                         offset = fPropertyIdentifier (tvb, subtree, offset);
2087                         break;
2088                 case 3: /* propertyArrayIndex */
2089                         offset = fUnsignedTag (tvb,subtree,offset,"Property Array Index: ");
2090                         break;
2091                 case 4: /* propertyValue */
2092                         if (tag_is_opening(tag_info)) {
2093                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
2094                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2095                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2096                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2097                                 break;
2098                         }
2099                         FAULT;
2100                         break;
2101                 case 5: /* priority */
2102                         offset = fUnsignedTag (tvb,subtree,offset,"Priority: ");
2103                         break;
2104                 case 6: /* postDelay */
2105                         offset = fUnsignedTag (tvb,subtree,offset,"Post Delay: ");
2106                         break;
2107                 case 7: /* quitOnFailure */
2108                         offset = fBooleanTag(tvb, subtree, offset,
2109                                 "Quit On Failure: ");
2110                         break;
2111                 case 8: /* writeSuccessful */
2112                         offset = fBooleanTag(tvb, subtree, offset,
2113                                 "Write Successful: ");
2114                         break;
2115                 default:
2116                         return offset;
2117                 }
2118         }
2119         return offset;
2120 }
2121
2122 static guint
2123 fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset)
2124 {
2125         return fActionCommand (tvb,tree,offset);
2126 }
2127
2128 static guint
2129 fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
2130 {
2131         guint8 tag_no, tag_info;
2132         guint32 lvt;
2133         guint tag_len;
2134         proto_item *ti;
2135         proto_tree *subtree;
2136
2137         propertyIdentifier = 0; /* global Variable */
2138         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2139         if (fUnsigned32 (tvb, offset+tag_len, lvt, &propertyIdentifier))
2140                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
2141                         "property Identifier: %s",
2142                         val_to_split_str(propertyIdentifier, 512,
2143                                 BACnetPropertyIdentifier,
2144                                 ASHRAE_Reserved_Fmt,
2145                                 Vendor_Proprietary_Fmt));
2146         else
2147                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
2148                 "Property Identifier - %u octets", lvt);
2149         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2150         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2151
2152         return offset+tag_len+lvt;
2153 }
2154
2155 static guint
2156 fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2157 {
2158         guint8 tag_no, tag_info, character_set;
2159         guint32 lvt, l;
2160         size_t inbytesleft, outbytesleft = 512;
2161         guint offs, extra = 1;
2162         guint8 *str_val;
2163         guint8 bf_arr[512], *out = &bf_arr[0];
2164         proto_item *ti;
2165         proto_tree *subtree;
2166     guint start = offset;
2167
2168         if (tvb_length_remaining(tvb, offset) > 0) {
2169
2170                 offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2171         
2172                 character_set = tvb_get_guint8(tvb, offset+offs);
2173         /* Account for code page if DBCS */
2174         if (character_set == 1)
2175         {
2176             extra = 3;
2177         }
2178         offset += (offs+extra);
2179         lvt -= (extra);
2180
2181                 do {
2182                         l = inbytesleft = min(lvt, 255);
2183                         /*
2184                          * XXX - are we guaranteed that these encoding
2185                          * names correspond, on *all* platforms with
2186                          * iconv(), to the encodings we want?
2187                          * If not (and perhaps even if so), we should
2188                          * perhaps have our own iconv() implementation,
2189                          * with a different name, so that we control the
2190                          * encodings it supports and the names of those
2191                          * encodings.
2192                          *
2193                          * We should also handle that in the general
2194                          * string handling code, rather than making it
2195                          * specific to the BACAPP dissector, as many
2196                          * other dissectors need to handle various
2197                          * character encodings.
2198                          */
2199                         str_val = tvb_get_ephemeral_string(tvb, offset, l);
2200                         /** this decoding may be not correct for multi-byte characters, Lka */
2201                         switch (character_set) {
2202                         case 0x00:      /* ANSI_X3.4 */
2203                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ANSI_X3.4");
2204                                 break;
2205                         case 1: /* IBM/MICROSOFT DBCS */
2206                                 out = str_val;
2207                                 break;
2208                         case 2: /* JIS C 6226 */
2209                                 out = str_val;
2210                                 break;
2211                         case 3: /* UCS-4 */
2212                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-4BE");
2213                                 break;
2214                         case 4: /* UCS-2 */
2215                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-2BE");
2216                                 break;
2217                         case 5: /* ISO8859-1 */
2218                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ISO8859-1");
2219                                 break;
2220                         default:
2221                                 out = str_val;
2222                                 break;
2223                         }
2224                         ti = proto_tree_add_text(tree, tvb, offset, l, "%s'%s'", label, out);
2225                         lvt-=l;
2226                         offset+=l;
2227                 } while (lvt > 0);
2228
2229                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2230
2231         fTagHeaderTree (tvb, subtree, start, &tag_no, &tag_info, &lvt);
2232                 proto_tree_add_item(subtree, hf_BACnetCharacterSet, tvb, start+offs, 1, FALSE);
2233         if (character_set == 1)
2234         {
2235             proto_tree_add_text(subtree, tvb, start+offs+1, 2, "Code Page: %d", tvb_get_ntohs(tvb, start+offs+1));
2236         }
2237         }
2238         return offset;
2239 }
2240
2241 static guint
2242 fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
2243         const value_string *src)
2244 {
2245         guint8 tag_no, tag_info, tmp;
2246         gint j, unused, skip;
2247         guint offs;
2248         guint32 lvt, i, numberOfBytes;
2249         guint8 bf_arr[256];
2250         
2251         offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2252         numberOfBytes = lvt-1; /* Ignore byte for unused bit count */
2253         offset+=offs;
2254         unused = tvb_get_guint8(tvb, offset); /* get the unused Bits */
2255         skip = 0;
2256         for (i = 0; i < numberOfBytes; i++) {
2257                 tmp = tvb_get_guint8(tvb, (offset)+i+1);
2258                 if (i == numberOfBytes-1) { skip = unused; }
2259                 for (j = 0; j < 8-skip; j++) {
2260                         if (src != NULL) {
2261                                 if (tmp & (1 << (7 - j)))
2262                                         proto_tree_add_text(tree, tvb,
2263                                                 offset+i+1, 1,
2264                                                 "%s%s = TRUE",
2265                                                 label,
2266                                                 val_to_str((guint) (i*8 +j),
2267                                                         src,
2268                                                         ASHRAE_Reserved_Fmt));
2269                                 else
2270                                         proto_tree_add_text(tree, tvb,
2271                                                 offset+i+1, 1,
2272                                                 "%s%s = FALSE",
2273                                                 label,
2274                                                 val_to_str((guint) (i*8 +j),
2275                                                         src,
2276                                                         ASHRAE_Reserved_Fmt));
2277
2278                         } else {
2279                                 bf_arr[min(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
2280                         }
2281                 }
2282         }
2283
2284         if (src == NULL)
2285         {
2286                 bf_arr[min(255,numberOfBytes*8-unused)] = 0;
2287                 proto_tree_add_text(tree, tvb, offset, lvt, "%sB'%s'", label, bf_arr);
2288         }
2289
2290         offset+=lvt;
2291         
2292         return offset;
2293 }
2294
2295 static guint
2296 fBitStringTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2297 {
2298         return fBitStringTagVS (tvb, tree, offset, label, NULL);
2299 }
2300
2301 /* handles generic application types, as well as enumerated and enumerations
2302    with reserved and proprietarty ranges (split) */  
2303 static guint
2304 fApplicationTypesEnumeratedSplit (tvbuff_t *tvb, proto_tree *tree, guint offset, 
2305         const gchar *label, const value_string *src, guint32 split_val)
2306 {
2307         guint8 tag_no, tag_info;
2308         guint32 lvt;
2309         guint tag_len;
2310
2311         if (tvb_length_remaining(tvb, offset) > 0) {
2312
2313                 tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2314         
2315                 switch (tag_no) {
2316                         case 0: /** NULL 20.2.2 */
2317                                 offset = fNullTag(tvb, tree, offset, label);
2318                                 break;
2319                         case 1: /** BOOLEAN 20.2.3 */
2320                                 offset = fBooleanTag(tvb, tree, offset, label);
2321                                 break;
2322                         case 2: /** Unsigned Integer 20.2.4 */
2323                                 offset = fUnsignedTag(tvb, tree, offset, label);
2324                                 break;
2325                         case 3: /** Signed Integer 20.2.5 */
2326                                 offset = fSignedTag(tvb, tree, offset, label);
2327                                 break;
2328                         case 4: /** Real 20.2.6 */
2329                                 offset = fRealTag(tvb, tree, offset, label);
2330                                 break;
2331                         case 5: /** Double 20.2.7 */
2332                                 offset = fDoubleTag(tvb, tree, offset, label);
2333                                 break;
2334                         case 6: /** Octet String 20.2.8 */
2335                                 offset = fOctetString (tvb, tree, offset, label, lvt);
2336                                 break;
2337                         case 7: /** Character String 20.2.9 */
2338                                 offset = fCharacterString (tvb,tree,offset,label);
2339                                 break;
2340                         case 8: /** Bit String 20.2.10 */
2341                                 offset = fBitStringTagVS (tvb, tree, offset, label, src);
2342                                 break;
2343                         case 9: /** Enumerated 20.2.11 */
2344                                 offset = fEnumeratedTagSplit (tvb, tree, offset, label, src, split_val);
2345                                 break;
2346                         case 10: /** Date 20.2.12 */
2347                                 offset = fDate (tvb, tree, offset, label);
2348                                 break;
2349                         case 11: /** Time 20.2.13 */
2350                                 offset = fTime (tvb, tree, offset, label);
2351                                 break;
2352                         case 12: /** BACnetObjectIdentifier 20.2.14 */
2353                                 offset = fObjectIdentifier (tvb, tree, offset);
2354                                 break;
2355                         case 13: /* reserved for ASHRAE */
2356                         case 14:
2357                         case 15:
2358                                 proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s'reserved for ASHRAE'", label);
2359                                 offset+=lvt+tag_len;
2360                                 break;
2361                         default:
2362                                 break;
2363                 }
2364         }
2365         return offset;
2366 }
2367
2368 static guint
2369 fApplicationTypesEnumerated (tvbuff_t *tvb, proto_tree *tree, guint offset, 
2370         const gchar *label, const value_string *vs)
2371 {
2372   return fApplicationTypesEnumeratedSplit(tvb, tree, offset, label, vs, 0);
2373 }
2374
2375 static guint
2376 fApplicationTypes (tvbuff_t *tvb, proto_tree *tree, guint offset, 
2377         const gchar *label)
2378 {
2379   return fApplicationTypesEnumeratedSplit(tvb, tree, offset, label, NULL, 0);
2380 }
2381
2382 static guint
2383 fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2384 {
2385         guint8 tag_no, tag_info;
2386         guint32 lvt;
2387         guint tag_len;
2388         proto_item *ti;
2389         proto_tree *subtree;
2390         gint tvb_len;
2391
2392         (void)label;
2393         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
2394         /* cap the the suggested length in case of bad data */
2395         tvb_len = tvb_length_remaining(tvb, offset+tag_len);
2396         if ((tvb_len >= 0) && ((guint32)tvb_len < lvt))
2397         {
2398                 lvt = tvb_len;
2399         }
2400         ti = proto_tree_add_text(tree, tvb, offset+tag_len, lvt,
2401                 "Context Value (as %u DATA octets)", lvt);
2402
2403         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2404         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2405         
2406         return offset + tag_len + lvt;
2407 }
2408
2409 static guint
2410 fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset)
2411 {
2412         guint8 tag_no, tag_info;
2413         guint32 lvt;
2414         guint lastoffset = 0, depth = 0;
2415         char ar[256];
2416         
2417         if (propertyIdentifier >= 0)
2418         {
2419                 g_snprintf (ar, sizeof(ar), "%s: ",
2420                         val_to_split_str(propertyIdentifier, 512,
2421                                 BACnetPropertyIdentifier,
2422                                 ASHRAE_Reserved_Fmt,
2423                                 Vendor_Proprietary_Fmt));
2424         }
2425         else
2426         {
2427                 g_snprintf (ar, sizeof(ar), "Abstract Type: ");
2428         }
2429         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2430                 lastoffset = offset;
2431                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2432                 if (tag_is_closing(tag_info)) { /* closing tag, but not for me */
2433                         if (depth <= 0) return offset;
2434                 }
2435
2436                 /* Application Tags */
2437                 switch (propertyIdentifier) {
2438                 case 2: /* BACnetActionList */
2439                         offset = fActionList (tvb,tree,offset);
2440                         break;
2441                 case 30: /* BACnetAddressBinding */
2442                         offset = fAddressBinding (tvb,tree,offset);
2443                         break;
2444                 case 79: /* object-type */
2445                 case 96: /* protocol-object-types-supported */
2446                         offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, ar, 
2447                                 BACnetObjectType, 128);
2448                         break;
2449                 case 97: /* Protocol-Services-Supported */
2450                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2451                                 BACnetServicesSupported);
2452                         break;
2453                 case 107: /* segmentation-supported */
2454                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2455                                 BACnetSegmentation);
2456                         break;
2457                 case 111: /* Status-Flags */
2458                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2459                                 BACnetStatusFlags);
2460                         break;
2461                 case 112: /* System-Status */
2462                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2463                                 BACnetDeviceStatus);
2464                         break;
2465                 case 117: /* units */
2466                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2467                                 BACnetEngineeringUnits);
2468                         break;
2469                 case 87:        /* priority-array */
2470                         offset = fPriorityArray (tvb, tree, offset);
2471                         break;
2472                 case 38:        /* exception-schedule */
2473                         if (object_type < 128)
2474                         {
2475                                 offset = fSpecialEvent (tvb,tree,offset);
2476                                 break;
2477                         }
2478                 case 123:       /* weekly-schedule */
2479                         if (object_type < 128)
2480                         {
2481                                 offset = fWeeklySchedule (tvb,tree,offset);
2482                                 break;
2483                         }
2484                 default:
2485                         if (tag_info)
2486                         {
2487                                 if (tag_is_opening(tag_info))
2488                                 {
2489                                         ++depth;
2490                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
2491                                 }
2492                                 else if (tag_is_closing(tag_info))
2493                                 {
2494                                         --depth;
2495                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
2496                                 }
2497                                 else
2498                                 {
2499                                         offset = fContextTaggedValue(tvb, tree, offset, ar);
2500                                 }
2501                         }
2502                         else
2503                         {
2504                                 offset = fApplicationTypes (tvb, tree, offset, ar);
2505                         }
2506                         break;
2507                 }
2508         }
2509         return offset;
2510
2511 }
2512
2513 static guint
2514 fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 tagoffset)
2515 {
2516         guint lastoffset = offset;
2517         proto_item *tt;
2518         proto_tree *subtree;
2519         guint8 tag_no, tag_info;
2520         guint32 lvt;
2521         
2522         offset = fPropertyReference(tvb, tree, offset, tagoffset, 0);
2523         if (offset > lastoffset)
2524         {
2525                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2526                 if (tag_no == tagoffset+2) {  /* Value - might not be present in ReadAccessResult */
2527                         if (tag_is_opening(tag_info)) {
2528                                 tt = proto_tree_add_text(tree, tvb, offset, 1, "propertyValue");
2529                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2530                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2531                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2532                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2533                         }
2534                 }
2535         }
2536         return offset;
2537 }
2538
2539 static guint
2540 fBACnetPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
2541 {
2542         guint lastoffset = 0;
2543         guint8 tag_no, tag_info;
2544         guint32 lvt;
2545
2546         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2547                 lastoffset = offset;
2548                 offset = fPropertyValue(tvb, tree, offset, 0);
2549                 if (offset > lastoffset)
2550                 {
2551                         /* detect optional priority
2552                         by looking to see if the next tag is context tag number 3 */
2553                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2554                         if (tag_is_context_specific(tag_info) && (tag_no == 3))
2555                                 offset = fUnsignedTag (tvb,tree,offset,"Priority: ");
2556                 }
2557         }
2558         return offset;
2559 }
2560
2561 static guint
2562 fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2563 {
2564         guint lastoffset = 0;
2565
2566         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2567                 lastoffset = offset;
2568         
2569                 switch (fTagNo(tvb,offset)) {
2570                 case 0: /* ProcessId */
2571                         offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
2572                         break;
2573                 case 1: /* monitored ObjectId */
2574                         offset = fObjectIdentifier (tvb, tree, offset);
2575                         break;
2576                 case 2: /* issueConfirmedNotifications */
2577                         offset = fBooleanTag (tvb, tree, offset, "issue Confirmed Notifications: ");
2578                         break;
2579                 case 3: /* life time */
2580                         offset = fTimeSpan (tvb,tree,offset,"life time");
2581                         break;
2582                 case 4: /* monitoredPropertyIdentifier */
2583                         offset = fBACnetPropertyReference (tvb, tree, offset, 0);
2584                         break;
2585                 case 5: /* covIncrement */
2586                         offset = fRealTag (tvb, tree, offset, "COV Increment: ");
2587                         break;
2588                 default:
2589                         return offset;
2590                         break;
2591                 }
2592         }
2593         return offset;
2594 }
2595
2596 static guint
2597 fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2598 {
2599         return fSubscribeCOVPropertyRequest(tvb, tree, offset);
2600 }
2601
2602 static guint
2603 fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset)
2604 {
2605         guint lastoffset = 0;
2606
2607         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2608                 lastoffset = offset;
2609         
2610                 switch (fTagNo(tvb, offset)) {
2611                 case 0: /* deviceInstanceLowLimit */
2612                         offset = fUnsignedTag (tvb, tree, offset, "device Instance Low Limit: ");
2613                         break;
2614                 case 1: /* deviceInstanceHighLimit */
2615                         offset = fUnsignedTag (tvb, tree, offset, "device Instance High Limit: ");
2616                         break;
2617                 case 2: /* BACnetObjectId */
2618                         offset = fObjectIdentifier (tvb, tree, offset);
2619                 break;
2620                 case 3: /* messageText */
2621                         offset = fCharacterString (tvb,tree,offset, "Object Name: ");
2622                         break;
2623                 default:
2624                         return offset;
2625                 }
2626         }
2627         return offset;
2628 }
2629
2630
2631 static guint
2632 fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset)
2633 {
2634         guint lastoffset = 0;
2635         guint8 tag_no, tag_info;
2636         guint32 lvt;
2637         
2638         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2639         if (tag_is_opening(tag_info) && tag_no == 0)
2640         {
2641                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); /* opening context tag 0 */
2642                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2643                         lastoffset = offset;
2644                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2645                         if (tag_is_closing(tag_info)) {
2646                                 /* should be closing context tag 0 */
2647                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2648                                 return offset;
2649                         }
2650                         
2651                         offset = fTimeValue (tvb, subtree, offset);
2652                 }
2653         }
2654         else if (tag_no == 0 && lvt == 0)
2655         {
2656                 /* not sure null (empty array element) is legal */
2657                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2658         }
2659         return offset;
2660 }
2661
2662 static guint
2663 fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset)
2664 {
2665         guint lastoffset = 0;
2666         guint8 tag_no, tag_info;
2667         guint32 lvt;
2668         guint i=1;
2669         proto_tree *subtree = tree;
2670         proto_item *tt;
2671         
2672         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2673                 lastoffset = offset;
2674                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2675                 if (tag_is_closing(tag_info)) {
2676                         return offset; /* outer encoding will print out closing tag */
2677                 }
2678                 tt = proto_tree_add_text(tree, tvb, offset, 0, val_to_str(i++, days, "day of week (%d) not found"));
2679                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2680                 offset = fDailySchedule (tvb,subtree,offset);
2681         }
2682         return offset;
2683 }
2684
2685
2686 static guint
2687 fUTCTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
2688 {
2689         if (tvb_length_remaining(tvb, offset) <= 0)
2690                 return offset;
2691         
2692         return fDateTime (tvb, tree, offset, "UTC-Time: ");
2693 }
2694
2695 static guint
2696 fTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
2697 {
2698         if (tvb_length_remaining(tvb, offset) <= 0)
2699                 return offset;
2700
2701         return fDateTime (tvb, tree, offset, NULL);
2702 }
2703
2704 static guint
2705 fDateRange  (tvbuff_t *tvb, proto_tree *tree, guint offset)
2706 {
2707         if (tvb_length_remaining(tvb, offset) <= 0)
2708                 return offset;
2709     offset = fDate (tvb,tree,offset,"Start Date: ");
2710         return fDate (tvb, tree, offset, "End Date: ");
2711 }
2712
2713 static guint
2714 fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2715 {
2716         guint lastoffset = 0;
2717
2718         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2719                 lastoffset = offset;
2720                 switch (fTagNo(tvb, offset)) {
2721
2722                 case 0: /* textMessageSourceDevice */
2723                         offset = fObjectIdentifier (tvb, tree, offset);
2724                         break;
2725                 case 1: /* messageClass */
2726                         switch (fTagNo(tvb, offset)) {
2727                         case 0: /* numeric */
2728                                 offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
2729                                 break;
2730                         case 1: /* character */
2731                                 offset = fCharacterString (tvb, tree, offset, "message Class: ");
2732                                 break;
2733                         }
2734                         break;
2735                 case 2: /* messagePriority */
2736                         offset = fEnumeratedTag (tvb, tree, offset, "message Priority: ",
2737                                 BACnetMessagePriority);
2738                         break;
2739                 case 3: /* message */
2740                         offset = fCharacterString (tvb, tree, offset, "message: ");
2741                         break;
2742                 default:
2743                         return offset;
2744                         break;  
2745                 }
2746         }
2747         return offset;
2748 }
2749
2750 static guint
2751 fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2752 {
2753         return fConfirmedTextMessageRequest(tvb, tree, offset);
2754 }
2755
2756 static guint
2757 fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2758 {
2759         guint lastoffset = 0;
2760         guint8 tag_no, tag_info;
2761         guint32 lvt;
2762         proto_tree *subtree = tree;
2763         proto_item *tt;
2764
2765         /* exit loop if nothing happens inside */ 
2766         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  
2767                 lastoffset = offset;
2768                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2769                 if (tag_is_closing(tag_info)) {
2770                         if (tag_no == 2) /* Make sure it's the expected tag */
2771                         {
2772                                 offset += fTagHeaderTree (tvb, subtree, offset,
2773                                         &tag_no, &tag_info, &lvt);
2774                                 subtree = tree;
2775                                 continue;
2776                         }
2777                         else
2778                         {
2779                                 break; /* End loop if incorrect closing tag */
2780                         }
2781                 }
2782                 switch (tag_no) {
2783
2784                 case 0: /* vendorID */
2785                         offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
2786                         break;
2787                 case 1: /* serviceNumber */
2788                         offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
2789                         break;
2790                 case 2: /*serviceParameters */
2791                         if (tag_is_opening(tag_info)) {
2792                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
2793                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2794                                 propertyIdentifier = -1;
2795                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2796                                 break;
2797                         }
2798                         FAULT;
2799                         break;
2800                 default:
2801                         return offset;
2802                 }
2803         }
2804         return offset;
2805 }
2806
2807 static guint
2808 fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2809 {
2810         return fConfirmedPrivateTransferRequest(tvb, tree, offset);
2811 }
2812
2813 static guint
2814 fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset)
2815 {
2816         return fConfirmedPrivateTransferRequest(tvb, tree, offset);
2817 }
2818
2819 static guint
2820 fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2821 {
2822         guint lastoffset = 0;
2823         guint8 tag_no, tag_info;
2824         guint32 lvt;
2825         proto_tree *subtree = tree;
2826         proto_item *tt;
2827
2828         if (label != NULL) {
2829                 tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", label);
2830                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2831         }
2832
2833         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2834                 lastoffset = offset;
2835                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2836         
2837                 switch (tag_no) {
2838                 case 0: /* subscriberProcessId */
2839                         offset = fUnsignedTag (tvb, subtree, offset, "requesting Process Id: ");
2840                         break;
2841                 case 1: /* requestingSource */
2842                         offset = fCharacterString (tvb, tree, offset, "requesting Source: ");
2843                         break;
2844                 case 2: /* request */
2845                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
2846                                 "request: ", BACnetLifeSafetyOperation, 64);
2847                         break;
2848                 case 3: /* objectId */
2849                         offset = fObjectIdentifier (tvb, subtree, offset);
2850                         break;
2851                 default:
2852                         return offset;
2853                         break;
2854                 }
2855         }
2856         return offset;
2857 }
2858
2859 static guint fBACnetPropertyStates(tvbuff_t *tvb, proto_tree *tree, guint offset)
2860 {
2861         switch (fTagNo(tvb, offset))
2862         {
2863         case 0:
2864                 offset = fBooleanTag (tvb, tree, offset, "boolean-value: ");
2865                 break;
2866         case 1:
2867                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2868                         "binary-value: ", BACnetBinaryPV, 2);
2869                 break;
2870         case 2:
2871                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2872                         "event-type: ", BACnetEventType, 12);
2873                 break;
2874         case 3:
2875                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2876                         "polarity: ", BACnetPolarity, 2);
2877                 break;
2878         case 4:
2879                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2880                         "program-change: ", BACnetProgramRequest, 5);
2881                 break;
2882         case 5:
2883                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2884                         "program-state: ", BACnetProgramState, 5);
2885                 break;
2886         case 6:
2887                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2888                         "reason-for-halt: ", BACnetProgramError, 5);
2889                 break;
2890         case 7:
2891                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2892                         "reliability: ", BACnetReliability, 10);
2893                 break;
2894         case 8:
2895                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2896                         "state: ", BACnetEventState, 64);
2897                 break;
2898         case 9:
2899                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2900                         "system-status: ", BACnetDeviceStatus, 64);
2901                 break;
2902         case 10:
2903                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2904                         "units: ", BACnetEngineeringUnits, 2);
2905                 break;
2906         case 11:
2907                 offset = fUnsignedTag(tvb, tree, offset, "unsigned-value: ");
2908                 break;
2909         case 12:
2910                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2911                         "life-safety-mode: ", BACnetLifeSafetyMode, 64);
2912                 break;
2913         case 13:
2914                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2915                         "life-safety-state: ", BACnetLifeSafetyState, 64);
2916                 break;
2917         default:
2918                 break;
2919         }
2920         return offset;
2921 }
2922
2923 static guint
2924 fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
2925 {
2926         guint lastoffset = offset;
2927         guint8 tag_no, tag_info;
2928         guint32 lvt;
2929         proto_tree *subtree = tree;
2930         proto_item *tt;
2931
2932         tt = proto_tree_add_text(subtree, tvb, offset, 0, "notification parameters");
2933         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2934         /* Opeing tag for parameter choice */
2935         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2936
2937         switch (tag_no) {
2938         case 0: /* change-of-bitstring */
2939                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2940                 lastoffset = offset;
2941                         switch (fTagNo(tvb, offset)) {
2942                         case 0:
2943                                 offset = fBitStringTag (tvb, subtree, offset, 
2944                                         "referenced-bitstring: ");
2945                                 break;
2946                         case 1:
2947                                 offset = fEnumeratedTag (tvb, subtree, offset, 
2948                                         "status-flags: ", BACnetStatusFlags);
2949                                 break;
2950                         default:
2951                                 return offset;
2952                                 break;
2953                         }
2954                 }
2955                 break;
2956         case 1: /* change-of-state */
2957                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2958                 lastoffset = offset;
2959                         switch (fTagNo(tvb, offset)) {
2960                         case 0:
2961                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2962                                 offset = fBACnetPropertyStates(tvb, subtree, offset);
2963                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2964                         case 1:
2965                                 offset = fEnumeratedTag (tvb, subtree, offset, 
2966                                         "status-flags: ", BACnetStatusFlags);
2967                         lastoffset = offset;
2968                                 break;
2969                         default:
2970                                 break;
2971                         }
2972                 }
2973                 break;
2974     case 2: /* change-of-value */
2975                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2976                 lastoffset = offset;
2977                         switch (fTagNo(tvb, offset)) {
2978                         case 0:
2979                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2980                                 switch (fTagNo(tvb, offset)) {
2981                                 case 0:
2982                                         offset = fBitStringTag (tvb, subtree, offset, 
2983                                                 "changed-bits: ");
2984                                         break;
2985                                 case 1:
2986                                         offset = fRealTag (tvb, subtree, offset, 
2987                                                 "changed-value: ");
2988                                         break;
2989                                 default:
2990                                         break;
2991                                 }
2992                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2993                                 break;
2994                         case 1:
2995                                 offset = fEnumeratedTag (tvb, subtree, offset, 
2996                                         "status-flags: ", BACnetStatusFlags);
2997                                 break;
2998                         default:
2999                                 break;
3000                         }
3001                 }
3002                 break;
3003     case 3: /* command-failure */
3004                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3005                 lastoffset = offset;
3006                         switch (fTagNo(tvb, offset)) {
3007                         case 0: /* "command-value: " */
3008                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3009                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3010                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3011                                 break;
3012                         case 1:
3013                                 offset = fEnumeratedTag (tvb, subtree, offset, 
3014                                         "status-flags: ", BACnetStatusFlags);
3015                         case 2: /* "feedback-value: " */
3016                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3017                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3018                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3019                         default:
3020                                 break;
3021                         }
3022                 }
3023                 break;
3024     case 4: /* floating-limit */
3025                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3026                 lastoffset = offset;
3027                         switch (fTagNo(tvb, offset)) {
3028                         case 0:
3029                                 offset = fRealTag (tvb, subtree, offset, "reference-value: ");
3030                                 break;
3031                         case 1:
3032                                 offset = fEnumeratedTag (tvb, subtree, offset, 
3033                                         "status-flags: ", BACnetStatusFlags);
3034                                 break;
3035                         case 2:
3036                                 offset = fRealTag (tvb, subtree, offset, "setpoint-value: ");
3037                                 break;
3038                         case 3:
3039                                 offset = fRealTag (tvb, subtree, offset, "error-limit: ");
3040                         default:
3041                                 break;
3042                         }
3043                 }
3044                 break;
3045     case 5: /* out-of-range */
3046                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3047                 lastoffset = offset;
3048                         switch (fTagNo(tvb, offset)) {
3049                         case 0:
3050                                 offset = fRealTag (tvb, subtree, offset, "exceeding-value: ");
3051                                 break;
3052                         case 1:
3053                                 offset = fEnumeratedTag (tvb, subtree, offset, 
3054                                         "status-flags: ", BACnetStatusFlags);
3055                                 break;
3056                         case 2:
3057                                 offset = fRealTag (tvb, subtree, offset, "deadband: ");
3058                                 break;
3059                         case 3:
3060                                 offset = fRealTag (tvb, subtree, offset, "exceeded-limit: ");
3061                         default:
3062                                 break;
3063                         }
3064                 }
3065             break;
3066         case 6:
3067                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3068                 lastoffset = offset;
3069                         offset =fBACnetPropertyValue (tvb,subtree,offset);
3070                 }
3071                 break;
3072         case 7: /* buffer-ready */
3073                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3074                 lastoffset = offset;
3075                         switch (fTagNo(tvb, offset)) {
3076                         case 0:
3077                                 offset = fObjectIdentifier (tvb, subtree, offset); /* buffer-device */
3078                                 break;
3079                         case 1:
3080                                 offset = fObjectIdentifier (tvb, subtree, offset); /* buffer-object */
3081                                 break;
3082                         case 2:
3083                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3084                                 offset = fDateTime (tvb, subtree, offset, "previous-notification: ");
3085                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3086                                 break;
3087                         case 3:
3088                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3089                                 offset = fDateTime (tvb, subtree, offset, "current-notification: ");
3090                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3091                         default:
3092                                 break;
3093                         }
3094                 }
3095                 break;
3096     case 8: /* change-of-life-safety */
3097                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3098                 lastoffset = offset;
3099                         switch (fTagNo(tvb, offset)) {
3100                         case 0:
3101                                 offset = fEnumeratedTagSplit (tvb, subtree, offset, 
3102                                         "new-state: ", BACnetLifeSafetyState, 256);
3103                                 break;
3104                         case 1:
3105                                 offset = fEnumeratedTagSplit (tvb, subtree, offset, 
3106                                         "new-mode: ", BACnetLifeSafetyState, 256);
3107                                 break;
3108                         case 2:
3109                                 offset = fEnumeratedTag (tvb, subtree, offset, 
3110                                         "status-flags: ", BACnetStatusFlags);
3111                         case 3:
3112                                 offset = fEnumeratedTagSplit (tvb, subtree, offset, 
3113                                         "operation-expected: ", BACnetLifeSafetyOperation, 64);
3114                         default:
3115                                 return offset;
3116                                 break;
3117                         }
3118                 }
3119             break;
3120         default:
3121                 break;
3122         }
3123         /* Closing tag for parameter choice */
3124         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3125
3126         return offset;
3127 }
3128
3129 #if 0
3130 static guint
3131 fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset)
3132 {
3133         guint lastoffset = 0;
3134
3135         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3136                 lastoffset = offset;
3137                 switch (fTagNo(tvb, offset)) {
3138                 case 0: /* change-of-bitstring */
3139                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3140                                 lastoffset = offset;
3141                                 switch (fTagNo(tvb, offset)) {
3142                                 case 0:
3143                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3144                                         break;
3145                                 case 1:
3146                                         offset = fBitStringTag (tvb, tree, offset, "bitmask: ");
3147                                         break;
3148                                 case 2: /* SEQUENCE OF BIT STRING */
3149                                         offset = fBitStringTagVS (tvb, tree, offset,
3150                                                 "bitstring value: ", BACnetEventTransitionBits);
3151                                         break;
3152                                 default:
3153                                         return offset;
3154                                 }
3155                         }
3156         break;
3157                 case 1: /* change-of-state */
3158                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3159                         lastoffset = offset;
3160                                 switch (fTagNo(tvb, offset)) {
3161                                 case 0:
3162                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3163                                         break;
3164                                 case 1: /* SEQUENCE OF BACnetPropertyStates */
3165                                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3166                                                 "value: ", BACnetPropertyStates, 64);
3167                                         break;
3168                                 default:
3169                                         return offset;
3170                                 }
3171                         }
3172                         break;
3173         case 2: /* change-of-value */
3174                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3175                         lastoffset = offset;
3176                                 switch (fTagNo(tvb, offset)) {
3177                                 case 0:
3178                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3179                                         break;
3180                                 case 1: /* don't loop it, it's a CHOICE */
3181                                         switch (fTagNo(tvb, offset)) {
3182                                         case 0:
3183                                                 offset = fBitStringTag (tvb, tree, offset, "bitmask: ");
3184                                                 break;
3185                                         case 1:
3186                                                 offset = fRealTag (tvb, tree, offset, 
3187                                                         "referenced Property Increment: ");
3188                                                 break;
3189                                         default:
3190                                                 return offset;
3191                                         }
3192                                 default:
3193                                         return offset;
3194                                 }
3195                         }
3196                 break;
3197         case 3: /* command-failure */
3198                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3199                         lastoffset = offset;
3200                                 switch (fTagNo(tvb, offset)) {
3201                                 case 0:
3202                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3203                                         break;
3204                                 case 1:
3205                                         offset = fDeviceObjectPropertyReference (tvb,tree,offset);
3206                                 default:
3207                                         return offset;
3208                                 }
3209                         }
3210         break;
3211         case 4: /* floating-limit */
3212                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3213                         lastoffset = offset;
3214                                 switch (fTagNo(tvb, offset)) {
3215                                 case 0:
3216                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3217                                         break;
3218                                 case 1:
3219                                         offset = fDeviceObjectPropertyReference (tvb,tree,offset);
3220                                         break;
3221                                 case 2:
3222                                         offset = fRealTag (tvb, tree, offset, "low diff limit: ");
3223                                         break;
3224                                 case 3:
3225                                         offset = fRealTag (tvb, tree, offset, "high diff limit: ");
3226                                         break;
3227                                 case 4:
3228                                         offset = fRealTag (tvb, tree, offset, "deadband: ");
3229                                         break;
3230                                 default:
3231                                         return offset;
3232                                 }
3233                         }
3234                         break;
3235                 case 5: /* out-of-range */
3236                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3237                                 lastoffset = offset;
3238                                 switch (fTagNo(tvb, offset)) {
3239                                 case 0:
3240                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3241                                         break;
3242                                 case 1:
3243                                         offset = fRealTag (tvb, tree, offset, "low limit: ");
3244                                         break;
3245                                 case 2:
3246                                         offset = fRealTag (tvb, tree, offset, "high limit: ");
3247                                         break;
3248                                 case 3:
3249                                         offset = fRealTag (tvb, tree, offset, "deadband: ");
3250                                         break;
3251                                 default:
3252                                         return offset;
3253                                 }
3254                         }
3255         break;
3256                 case 6:
3257                         offset = fBACnetPropertyValue (tvb,tree,offset);
3258                         break;
3259                 case 7: /* buffer-ready */
3260                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3261                                 lastoffset = offset;
3262                                 switch (fTagNo(tvb, offset)) {
3263                                 case 0:
3264                                         offset = fUnsignedTag (tvb,tree,offset,"notification threshold");
3265                                         break;
3266                                 case 1:
3267                                         offset = fUnsignedTag (tvb,tree,offset,
3268                                                 "previous notification count: ");
3269                                         break;
3270                                 default:
3271                                         return offset;
3272                                 }
3273                         }
3274         break;
3275                 case 8: /* change-of-life-safety */
3276                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3277                                 lastoffset = offset;
3278                                 switch (fTagNo(tvb, offset)) {
3279                                 case 0:
3280                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3281                                         break;
3282                                 case 1:
3283                                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3284                                                 "life safety alarm value: ", BACnetLifeSafetyState, 256);
3285                                         break;
3286                                 case 2:
3287                                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3288                                                 "alarm value: ", BACnetLifeSafetyState, 256);
3289                                         break;
3290                                 case 3:
3291                                         offset = fDeviceObjectPropertyReference (tvb, tree, offset);
3292                                         break;
3293                                 default:
3294                                         return offset;
3295                                 }
3296                         }
3297                         break;
3298                 default:
3299                         return offset;
3300                 }
3301         }
3302         return offset;
3303 }
3304
3305 static guint
3306 fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset)
3307 {
3308         guint lastoffset = 0;
3309
3310         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3311                 lastoffset = offset;
3312                 switch (fTagNo(tvb, offset)) {
3313                 case 0: /* timestamp */
3314                         offset = fDateTime (tvb,tree,offset,NULL);
3315                         break;
3316                 case 1: /* logDatum: don't loop, it's a CHOICE */
3317                         switch (fTagNo(tvb, offset)) {
3318                         case 0: /* logStatus */
3319                                 offset = fEnumeratedTag (tvb, tree, offset, 
3320                                         "log status: ", BACnetLogStatus);
3321                                 break;
3322                         case 1:
3323                                 offset = fBooleanTag (tvb, tree, offset, "boolean-value: ");
3324                                 break;
3325                         case 2:
3326                                 offset = fRealTag (tvb, tree, offset, "real value: ");
3327                                 break;
3328                         case 3:
3329                                 offset = fUnsignedTag (tvb, tree, offset, "enum value: ");
3330                                 break;
3331                         case 4:
3332                                 offset = fUnsignedTag (tvb, tree, offset, "unsigned value: ");
3333                                 break;
3334                         case 5:
3335                                 offset = fSignedTag (tvb, tree, offset, "signed value: ");
3336                                 break;
3337                         case 6:
3338                                 offset = fBitStringTag (tvb, tree, offset, "bitstring value: ");
3339                                 break;
3340                         case 7:
3341                                 offset = fNullTag(tvb, tree, offset, "null value: ");
3342                                 break;
3343                         case 8:
3344                                 offset = fError (tvb,tree,offset);
3345                                 break;
3346                         case 9:
3347                                 offset = fRealTag (tvb, tree, offset, "time change: ");
3348                                 break;
3349                         case 10:        /* any Value */
3350                                 offset = fAbstractSyntaxNType (tvb, tree, offset);
3351                                 break;
3352                         default:
3353                                 return offset;
3354                         }
3355         break;
3356                 case 2:
3357                         offset = fEnumeratedTag (tvb, tree, offset, 
3358                                 "status Flags: ", BACnetStatusFlags);
3359                         break;
3360                 default:
3361                         return offset;
3362                 }
3363         }
3364         return offset;
3365 }
3366 #endif
3367
3368 static guint
3369 fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3370 {
3371         guint lastoffset = 0;
3372         guint8 tag_no, tag_info;
3373         guint32 lvt;
3374
3375         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3376                 lastoffset = offset;
3377         
3378                 switch (fTagNo(tvb,offset)) {
3379                 case 0: /* ProcessId */
3380                         offset = fProcessId (tvb,tree,offset);
3381                         break;
3382                 case 1: /* initiating ObjectId */
3383                         offset = fObjectIdentifier (tvb, tree, offset);
3384                         break;
3385                 case 2: /* event ObjectId */
3386                         offset = fObjectIdentifier (tvb, tree, offset);
3387                         break;
3388                 case 3: /* time stamp */
3389                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3390                         offset = fTimeStamp (tvb, tree, offset);
3391                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3392                         break;
3393                 case 4: /* notificationClass */
3394                         offset = fUnsignedTag (tvb, tree, offset, "Notification Class: ");
3395                         break;
3396                 case 5: /* Priority */
3397                         offset = fUnsignedTag (tvb, tree, offset, "Priority: ");
3398                         break;
3399                 case 6: /* EventType */
3400                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3401                                 "Event Type: ", BACnetEventType, 64);
3402                         break;
3403                 case 7: /* messageText */
3404                         offset = fCharacterString (tvb, tree, offset, "message Text: ");
3405                         break;
3406                 case 8: /* NotifyType */
3407                         offset = fEnumeratedTag (tvb, tree, offset,
3408                                 "Notify Type: ", BACnetNotifyType);
3409                         break;
3410                 case 9: /* ackRequired */