Bill Meier: More spelling fixes
[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) + 1900;
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                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1725                         "%sany", label);
1726         else
1727                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1728                         "%s%s %d, %d, (Day of Week = %s)",
1729                         label, val_to_str(month,
1730                                 months,
1731                                 "month (%d) not found"),
1732                         day, year, val_to_str(weekday,
1733                                 days,
1734                                 "(%d) not found"));
1735         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1736         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1737
1738         return offset+tag_len+lvt;
1739 }
1740
1741 static guint
1742 fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1743 {
1744         guint32 year, month, day, weekday, lvt;
1745         guint8 tag_no, tag_info;
1746         guint tag_len;
1747         proto_item *ti;
1748         proto_tree *subtree;
1749
1750         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1751         year = tvb_get_guint8(tvb, offset+tag_len);
1752         month = tvb_get_guint8(tvb, offset+tag_len+1);
1753         day = tvb_get_guint8(tvb, offset+tag_len+2);
1754         weekday = tvb_get_guint8(tvb, offset+tag_len+3);
1755         if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255))
1756                 ti = proto_tree_add_text(tree, tvb, offset,
1757                         lvt+tag_len, "%sany", label);
1758         else
1759                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
1760                         "%s%d:%02d:%02d.%d %s = %02d:%02d:%02d.%d",
1761                         label,
1762                         year > 12 ? year -12 : year,
1763                         month, day, weekday,
1764                         year > 12 ? "P.M." : "A.M.",
1765                         year, month, day, weekday);
1766         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1767         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1768         
1769         return offset+tag_len+lvt;
1770 }
1771
1772 static guint
1773 fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
1774 {
1775         proto_tree *subtree = tree;
1776         proto_item *tt;
1777
1778         if (label != NULL) {
1779                 tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", label);
1780                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
1781         }
1782         offset = fDate (tvb,subtree,offset,"Date: ");
1783         return fTime (tvb,subtree,offset,"Time: ");
1784 }
1785
1786 static guint
1787 fTimeValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
1788 {
1789         guint lastoffset = 0;
1790         guint8 tag_no, tag_info;
1791         guint32 lvt;                               
1792
1793         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
1794                 lastoffset = offset;
1795                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1796                 if (tag_is_closing(tag_info)) {   /* closing Tag, but not for me */
1797                         return offset;
1798                 }
1799                 offset = fTime    (tvb,tree,offset,"Time: ");
1800                 offset = fApplicationTypes(tvb, tree, offset, "Value: ");
1801         }
1802         return offset;
1803 }
1804
1805 static guint
1806 fCalendaryEntry (tvbuff_t *tvb, proto_tree *tree, guint offset)
1807 {
1808         guint lastoffset = 0;
1809
1810         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
1811                 lastoffset = offset;
1812         
1813                 switch (fTagNo(tvb, offset)) {
1814                 case 0: /* Date */
1815                         offset = fDate    (tvb, tree, offset, "Date: ");
1816                         break;
1817                 case 1: /* dateRange */
1818                         offset = fDateRange (tvb, tree, offset);
1819                         break;
1820                 case 2: /* BACnetWeekNDay */
1821                         offset = fWeekNDay (tvb, tree, offset);
1822                         break;
1823                 default:
1824                         return offset;
1825                         break;
1826                 }
1827         }
1828         return offset;
1829 }
1830
1831 static guint
1832 fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset)
1833 {
1834         guint8 tag_no = 0, tag_info = 0;
1835         guint32 lvt = 0;
1836
1837         if (tvb_length_remaining(tvb, offset) > 0) {    /* don't loop, it's a CHOICE */
1838                 switch (fTagNo(tvb, offset)) {
1839                 case 0: /* time */
1840                         offset = fTime (tvb, tree, offset, "timestamp: ");
1841                         break;
1842                 case 1: /* sequenceNumber */
1843                         offset = fUnsignedTag (tvb, tree, offset, "sequence Number: ");
1844                         break;
1845                 case 2: /* dateTime */
1846                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
1847                         offset = fDateTime (tvb, tree, offset, "timestamp: ");
1848                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
1849                         break;
1850                 default:
1851                         return offset;
1852                         break;
1853                 }
1854         }
1855         return offset;
1856 }
1857
1858 #if 0
1859 static guint
1860 fSetpointReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
1861 {
1862         guint lastoffset = 0;
1863
1864         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
1865                 lastoffset = offset;
1866         
1867                 switch (fTagNo(tvb, offset)) {
1868                 case 0: /* setpointReference */
1869                         offset = fBACnetObjectPropertyReference (tvb,tree,offset);
1870                         break;
1871                 default:
1872                         return offset;
1873                         break;
1874                 }
1875         }
1876         return offset;
1877 }
1878 #endif
1879
1880 #if 0
1881 static guint
1882 fClientCOV (tvbuff_t *tvb, proto_tree *tree, guint offset)
1883 {
1884         if (tvb_length_remaining(tvb, offset) > 0) {
1885         offset = fApplicationTypes(tvb,tree,offset, "increment: ");
1886     }
1887     return offset;
1888 }
1889
1890 static guint
1891 fDestination (tvbuff_t *tvb, proto_tree *tree, guint offset)
1892 {
1893         if (tvb_length_remaining(tvb, offset) > 0) {
1894                 offset = fApplicationTypesEnumerated(tvb,tree,offset, 
1895                         "valid Days: ", days);
1896                 offset = fTime (tvb,tree,offset,"from time: ");
1897                 offset = fTime (tvb,tree,offset,"to time: ");
1898                 offset = fRecipient (tvb,tree,offset);
1899                 offset = fProcessId (tvb,tree,offset);
1900                 offset = fApplicationTypes (tvb,tree,offset,
1901                         "issue confirmed notifications: ");
1902                 offset = fApplicationTypesEnumerated (tvb,tree,offset,
1903                         "transitions: ", BACnetEventTransitionBits);
1904         }
1905         return offset;
1906 }
1907
1908 #endif
1909
1910 static guint
1911 fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, guint32 lvt)
1912 {
1913         gchar *tmp;
1914     guint start = offset;
1915         guint8 tag_no, tag_info;
1916     proto_tree* subtree = tree;
1917     proto_item* ti = 0;
1918
1919         offset += fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1920
1921         if (lvt > 0)
1922     {
1923             tmp = tvb_bytes_to_str(tvb, offset, lvt);
1924             ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s %s", label, tmp);
1925                 offset += lvt;
1926     }
1927
1928         if (ti)
1929         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1930
1931     fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt);
1932
1933         return offset;
1934 }
1935
1936 static guint
1937 fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset)
1938 {
1939         guint8 tag_no, tag_info;
1940         guint32 lvt;
1941     guint offs;
1942
1943         offset = fUnsignedTag (tvb, tree, offset, "network-number");
1944         offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
1945         if (lvt == 0) {
1946                 proto_tree_add_text(tree, tvb, offset, offs, "mac-address: broadcast");
1947                 offset += offs;
1948         } else
1949                 offset = fOctetString (tvb, tree, offset, "mac-address: ", lvt);
1950         return offset;
1951 }
1952
1953 #if 0
1954 static guint
1955 fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset)
1956 {
1957         offset = fOctetString (tvb,tree,offset,"session key: ", 8);
1958         return fAddress (tvb,tree,offset);
1959 }
1960 #endif
1961
1962 static guint
1963 fObjectIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
1964 {
1965         guint8  tag_no, tag_info;
1966         guint32 lvt;
1967         guint tag_length;
1968         proto_item *ti;
1969         proto_tree *subtree;
1970         guint32 object_id;
1971
1972         tag_length = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
1973         object_id = tvb_get_ntohl(tvb,offset+tag_length);
1974         object_type = object_id_type(object_id);
1975         ti = proto_tree_add_text(tree, tvb, offset, tag_length + 4,
1976                 "ObjectIdentifier: %s, %u",
1977                 val_to_split_str(object_type,
1978                         128,
1979                         BACnetObjectType,
1980                         ASHRAE_Reserved_Fmt,
1981                         Vendor_Proprietary_Fmt),
1982                 object_id_instance(object_id));
1983         /* here are the details of how we arrived at the above text */
1984         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
1985         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
1986         offset += tag_length;
1987         proto_tree_add_item(subtree, hf_bacapp_objectType, tvb, offset, 4, FALSE);
1988         proto_tree_add_item(subtree, hf_bacapp_instanceNumber, tvb, offset, 4, FALSE);
1989         offset += 4;
1990
1991         return offset;
1992 }
1993
1994 static guint
1995 fRecipient (tvbuff_t *tvb, proto_tree *tree, guint offset)
1996 {
1997         guint lastoffset = 0;
1998
1999         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2000                 lastoffset = offset;
2001         
2002                 switch (fTagNo(tvb, offset)) {
2003                 case 0: /* device */
2004                         offset = fObjectIdentifier (tvb, tree, offset);
2005                         break;
2006                 case 1: /* address */
2007                         offset = fAddress (tvb, tree, offset);
2008                         break;
2009                 default:
2010                         return offset;
2011                         break;
2012                 }
2013         }
2014         return offset;
2015 }
2016
2017 static guint
2018 fRecipientProcess (tvbuff_t *tvb, proto_tree *tree, guint offset)
2019 {
2020         guint lastoffset = 0;
2021
2022         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2023                 lastoffset = offset;
2024         
2025                 switch (fTagNo(tvb, offset)) {
2026                 case 0: /* recipient */
2027                         offset = fRecipient (tvb, tree, offset);
2028                         break;
2029                 case 1: /* processId */
2030                         offset = fProcessId (tvb, tree, offset);
2031                         break;
2032                 default:
2033                         return offset;
2034                         break;
2035                 }
2036         }
2037         return offset;
2038 }
2039
2040 static guint
2041 fAddressBinding (tvbuff_t *tvb, proto_tree *tree, guint offset)
2042 {
2043         offset = fObjectIdentifier (tvb, tree, offset);
2044         return fAddress (tvb, tree, offset);
2045 }
2046
2047 static guint
2048 fActionCommand (tvbuff_t *tvb, proto_tree *tree, guint offset)
2049 {
2050         guint lastoffset = 0;
2051         guint8 tag_no, tag_info;
2052         guint32 lvt;
2053         proto_tree *subtree = tree;
2054         proto_item *tt;
2055
2056         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2057                 lastoffset = offset;
2058                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2059                 if (tag_is_closing(tag_info)) {  
2060                         offset += fTagHeaderTree (tvb, subtree, offset,
2061                                 &tag_no, &tag_info, &lvt);
2062                         subtree = tree;
2063                         continue;
2064                 }
2065                 switch (tag_no) {
2066         
2067                 case 0: /* deviceIdentifier */
2068                         offset = fObjectIdentifier (tvb, subtree, offset);
2069                         break;
2070                 case 1: /* objectIdentifier */
2071                         offset = fObjectIdentifier (tvb, subtree, offset);
2072                         break;
2073                 case 2: /* propertyIdentifier */
2074                         offset = fPropertyIdentifier (tvb, subtree, offset);
2075                         break;
2076                 case 3: /* propertyArrayIndex */
2077                         offset = fUnsignedTag (tvb,subtree,offset,"Property Array Index: ");
2078                         break;
2079                 case 4: /* propertyValue */
2080                         if (tag_is_opening(tag_info)) {
2081                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
2082                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2083                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2084                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2085                                 break;
2086                         }
2087                         FAULT;
2088                         break;
2089                 case 5: /* priority */
2090                         offset = fUnsignedTag (tvb,subtree,offset,"Priority: ");
2091                         break;
2092                 case 6: /* postDelay */
2093                         offset = fUnsignedTag (tvb,subtree,offset,"Post Delay: ");
2094                         break;
2095                 case 7: /* quitOnFailure */
2096                         offset = fBooleanTag(tvb, subtree, offset,
2097                                 "Quit On Failure: ");
2098                         break;
2099                 case 8: /* writeSuccessful */
2100                         offset = fBooleanTag(tvb, subtree, offset,
2101                                 "Write Successful: ");
2102                         break;
2103                 default:
2104                         return offset;
2105                 }
2106         }
2107         return offset;
2108 }
2109
2110 static guint
2111 fActionList (tvbuff_t *tvb, proto_tree *tree, guint offset)
2112 {
2113         return fActionCommand (tvb,tree,offset);
2114 }
2115
2116 static guint
2117 fPropertyIdentifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
2118 {
2119         guint8 tag_no, tag_info;
2120         guint32 lvt;
2121         guint tag_len;
2122         proto_item *ti;
2123         proto_tree *subtree;
2124
2125         propertyIdentifier = 0; /* global Variable */
2126         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2127         if (fUnsigned32 (tvb, offset+tag_len, lvt, &propertyIdentifier))
2128                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
2129                         "property Identifier: %s",
2130                         val_to_split_str(propertyIdentifier, 512,
2131                                 BACnetPropertyIdentifier,
2132                                 ASHRAE_Reserved_Fmt,
2133                                 Vendor_Proprietary_Fmt));
2134         else
2135                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
2136                 "Property Identifier - %u octets", lvt);
2137         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2138         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2139
2140         return offset+tag_len+lvt;
2141 }
2142
2143 static guint
2144 fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2145 {
2146         guint8 tag_no, tag_info, character_set;
2147         guint32 lvt, l;
2148         size_t inbytesleft, outbytesleft = 512;
2149         guint offs, extra = 1;
2150         guint8 *str_val;
2151         guint8 bf_arr[512], *out = &bf_arr[0];
2152         proto_item *ti;
2153         proto_tree *subtree;
2154     guint start = offset;
2155
2156         if (tvb_length_remaining(tvb, offset) > 0) {
2157
2158                 offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2159         
2160                 character_set = tvb_get_guint8(tvb, offset+offs);
2161         /* Account for code page if DBCS */
2162         if (character_set == 1)
2163         {
2164             extra = 3;
2165         }
2166         offset += (offs+extra);
2167         lvt -= (extra);
2168
2169                 do {
2170                         l = inbytesleft = min(lvt, 255);
2171                         /*
2172                          * XXX - are we guaranteed that these encoding
2173                          * names correspond, on *all* platforms with
2174                          * iconv(), to the encodings we want?
2175                          * If not (and perhaps even if so), we should
2176                          * perhaps have our own iconv() implementation,
2177                          * with a different name, so that we control the
2178                          * encodings it supports and the names of those
2179                          * encodings.
2180                          *
2181                          * We should also handle that in the general
2182                          * string handling code, rather than making it
2183                          * specific to the BACAPP dissector, as many
2184                          * other dissectors need to handle various
2185                          * character encodings.
2186                          */
2187                         str_val = tvb_get_ephemeral_string(tvb, offset, l);
2188                         /** this decoding may be not correct for multi-byte characters, Lka */
2189                         switch (character_set) {
2190                         case 0x00:      /* ANSI_X3.4 */
2191                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ANSI_X3.4");
2192                                 break;
2193                         case 1: /* IBM/MICROSOFT DBCS */
2194                                 out = str_val;
2195                                 break;
2196                         case 2: /* JIS C 6226 */
2197                                 out = str_val;
2198                                 break;
2199                         case 3: /* UCS-4 */
2200                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-4BE");
2201                                 break;
2202                         case 4: /* UCS-2 */
2203                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-2BE");
2204                                 break;
2205                         case 5: /* ISO8859-1 */
2206                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ISO8859-1");
2207                                 break;
2208                         default:
2209                                 out = str_val;
2210                                 break;
2211                         }
2212                         ti = proto_tree_add_text(tree, tvb, offset, l, "%s'%s'", label, out);
2213                         lvt-=l;
2214                         offset+=l;
2215                 } while (lvt > 0);
2216
2217                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2218
2219         fTagHeaderTree (tvb, subtree, start, &tag_no, &tag_info, &lvt);
2220                 proto_tree_add_item(subtree, hf_BACnetCharacterSet, tvb, start+offs, 1, FALSE);
2221         if (character_set == 1)
2222         {
2223             proto_tree_add_text(subtree, tvb, start+offs+1, 2, "Code Page: %d", tvb_get_ntohs(tvb, start+offs+1));
2224         }
2225         }
2226         return offset;
2227 }
2228
2229 static guint
2230 fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
2231         const value_string *src)
2232 {
2233         guint8 tag_no, tag_info, tmp;
2234         gint j, unused, skip;
2235         guint offs;
2236         guint32 lvt, i, numberOfBytes;
2237         guint8 bf_arr[256];
2238         
2239         offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2240         numberOfBytes = lvt-1; /* Ignore byte for unused bit count */
2241         offset+=offs;
2242         unused = tvb_get_guint8(tvb, offset); /* get the unused Bits */
2243         skip = 0;
2244         for (i = 0; i < numberOfBytes; i++) {
2245                 tmp = tvb_get_guint8(tvb, (offset)+i+1);
2246                 if (i == numberOfBytes-1) { skip = unused; }
2247                 for (j = 0; j < 8-skip; j++) {
2248                         if (src != NULL) {
2249                                 if (tmp & (1 << (7 - j)))
2250                                         proto_tree_add_text(tree, tvb,
2251                                                 offset+i+1, 1,
2252                                                 "%s%s = TRUE",
2253                                                 label,
2254                                                 val_to_str((guint) (i*8 +j),
2255                                                         src,
2256                                                         ASHRAE_Reserved_Fmt));
2257                                 else
2258                                         proto_tree_add_text(tree, tvb,
2259                                                 offset+i+1, 1,
2260                                                 "%s%s = FALSE",
2261                                                 label,
2262                                                 val_to_str((guint) (i*8 +j),
2263                                                         src,
2264                                                         ASHRAE_Reserved_Fmt));
2265
2266                         } else {
2267                                 bf_arr[min(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
2268                         }
2269                 }
2270         }
2271
2272         if (src == NULL)
2273         {
2274                 bf_arr[min(255,numberOfBytes*8-unused)] = 0;
2275                 proto_tree_add_text(tree, tvb, offset, lvt, "%sB'%s'", label, bf_arr);
2276         }
2277
2278         offset+=lvt;
2279         
2280         return offset;
2281 }
2282
2283 static guint
2284 fBitStringTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2285 {
2286         return fBitStringTagVS (tvb, tree, offset, label, NULL);
2287 }
2288
2289 /* handles generic application types, as well as enumerated and enumerations
2290    with reserved and proprietarty ranges (split) */  
2291 static guint
2292 fApplicationTypesEnumeratedSplit (tvbuff_t *tvb, proto_tree *tree, guint offset, 
2293         const gchar *label, const value_string *src, guint32 split_val)
2294 {
2295         guint8 tag_no, tag_info;
2296         guint32 lvt;
2297         guint tag_len;
2298
2299         if (tvb_length_remaining(tvb, offset) > 0) {
2300
2301                 tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2302         
2303                 switch (tag_no) {
2304                         case 0: /** NULL 20.2.2 */
2305                                 offset = fNullTag(tvb, tree, offset, label);
2306                                 break;
2307                         case 1: /** BOOLEAN 20.2.3 */
2308                                 offset = fBooleanTag(tvb, tree, offset, label);
2309                                 break;
2310                         case 2: /** Unsigned Integer 20.2.4 */
2311                                 offset = fUnsignedTag(tvb, tree, offset, label);
2312                                 break;
2313                         case 3: /** Signed Integer 20.2.5 */
2314                                 offset = fSignedTag(tvb, tree, offset, label);
2315                                 break;
2316                         case 4: /** Real 20.2.6 */
2317                                 offset = fRealTag(tvb, tree, offset, label);
2318                                 break;
2319                         case 5: /** Double 20.2.7 */
2320                                 offset = fDoubleTag(tvb, tree, offset, label);
2321                                 break;
2322                         case 6: /** Octet String 20.2.8 */
2323                                 offset = fOctetString (tvb, tree, offset, label, lvt);
2324                                 break;
2325                         case 7: /** Character String 20.2.9 */
2326                                 offset = fCharacterString (tvb,tree,offset,label);
2327                                 break;
2328                         case 8: /** Bit String 20.2.10 */
2329                                 offset = fBitStringTagVS (tvb, tree, offset, label, src);
2330                                 break;
2331                         case 9: /** Enumerated 20.2.11 */
2332                                 offset = fEnumeratedTagSplit (tvb, tree, offset, label, src, split_val);
2333                                 break;
2334                         case 10: /** Date 20.2.12 */
2335                                 offset = fDate (tvb, tree, offset, label);
2336                                 break;
2337                         case 11: /** Time 20.2.13 */
2338                                 offset = fTime (tvb, tree, offset, label);
2339                                 break;
2340                         case 12: /** BACnetObjectIdentifier 20.2.14 */
2341                                 offset = fObjectIdentifier (tvb, tree, offset);
2342                                 break;
2343                         case 13: /* reserved for ASHRAE */
2344                         case 14:
2345                         case 15:
2346                                 proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s'reserved for ASHRAE'", label);
2347                                 offset+=lvt+tag_len;
2348                                 break;
2349                         default:
2350                                 break;
2351                 }
2352         }
2353         return offset;
2354 }
2355
2356 static guint
2357 fApplicationTypesEnumerated (tvbuff_t *tvb, proto_tree *tree, guint offset, 
2358         const gchar *label, const value_string *vs)
2359 {
2360   return fApplicationTypesEnumeratedSplit(tvb, tree, offset, label, vs, 0);
2361 }
2362
2363 static guint
2364 fApplicationTypes (tvbuff_t *tvb, proto_tree *tree, guint offset, 
2365         const gchar *label)
2366 {
2367   return fApplicationTypesEnumeratedSplit(tvb, tree, offset, label, NULL, 0);
2368 }
2369
2370 static guint
2371 fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2372 {
2373         guint8 tag_no, tag_info;
2374         guint32 lvt;
2375         guint tag_len;
2376         proto_item *ti;
2377         proto_tree *subtree;
2378         gint tvb_len;
2379
2380         (void)label;
2381         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
2382         /* cap the the suggested length in case of bad data */
2383         tvb_len = tvb_length_remaining(tvb, offset+tag_len);
2384         if ((tvb_len >= 0) && ((guint32)tvb_len < lvt))
2385         {
2386                 lvt = tvb_len;
2387         }
2388         ti = proto_tree_add_text(tree, tvb, offset+tag_len, lvt,
2389                 "Context Value (as %u DATA octets)", lvt);
2390
2391         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
2392         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2393         
2394         return offset + tag_len + lvt;
2395 }
2396
2397 static guint
2398 fAbstractSyntaxNType (tvbuff_t *tvb, proto_tree *tree, guint offset)
2399 {
2400         guint8 tag_no, tag_info;
2401         guint32 lvt;
2402         guint lastoffset = 0, depth = 0;
2403         char ar[256];
2404         
2405         if (propertyIdentifier >= 0)
2406         {
2407                 g_snprintf (ar, sizeof(ar), "%s: ",
2408                         val_to_split_str(propertyIdentifier, 512,
2409                                 BACnetPropertyIdentifier,
2410                                 ASHRAE_Reserved_Fmt,
2411                                 Vendor_Proprietary_Fmt));
2412         }
2413         else
2414         {
2415                 g_snprintf (ar, sizeof(ar), "Abstract Type: ");
2416         }
2417         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2418                 lastoffset = offset;
2419                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2420                 if (tag_is_closing(tag_info)) { /* closing tag, but not for me */
2421                         if (depth <= 0) return offset;
2422                 }
2423
2424                 /* Application Tags */
2425                 switch (propertyIdentifier) {
2426                 case 2: /* BACnetActionList */
2427                         offset = fActionList (tvb,tree,offset);
2428                         break;
2429                 case 30: /* BACnetAddressBinding */
2430                         offset = fAddressBinding (tvb,tree,offset);
2431                         break;
2432                 case 79: /* object-type */
2433                 case 96: /* protocol-object-types-supported */
2434                         offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, ar, 
2435                                 BACnetObjectType, 128);
2436                         break;
2437                 case 97: /* Protocol-Services-Supported */
2438                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2439                                 BACnetServicesSupported);
2440                         break;
2441                 case 107: /* segmentation-supported */
2442                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2443                                 BACnetSegmentation);
2444                         break;
2445                 case 111: /* Status-Flags */
2446                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2447                                 BACnetStatusFlags);
2448                         break;
2449                 case 112: /* System-Status */
2450                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2451                                 BACnetDeviceStatus);
2452                         break;
2453                 case 117: /* units */
2454                         offset = fApplicationTypesEnumerated (tvb, tree, offset, ar, 
2455                                 BACnetEngineeringUnits);
2456                         break;
2457                 case 87:        /* priority-array */
2458                         offset = fPriorityArray (tvb, tree, offset);
2459                         break;
2460                 case 38:        /* exception-schedule */
2461                         if (object_type < 128)
2462                         {
2463                                 offset = fSpecialEvent (tvb,tree,offset);
2464                                 break;
2465                         }
2466                 case 123:       /* weekly-schedule */
2467                         if (object_type < 128)
2468                         {
2469                                 offset = fWeeklySchedule (tvb,tree,offset);
2470                                 break;
2471                         }
2472                 default:
2473                         if (tag_info)
2474                         {
2475                                 if (tag_is_opening(tag_info))
2476                                 {
2477                                         ++depth;
2478                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
2479                                 }
2480                                 else if (tag_is_closing(tag_info))
2481                                 {
2482                                         --depth;
2483                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
2484                                 }
2485                                 else
2486                                 {
2487                                         offset = fContextTaggedValue(tvb, tree, offset, ar);
2488                                 }
2489                         }
2490                         else
2491                         {
2492                                 offset = fApplicationTypes (tvb, tree, offset, ar);
2493                         }
2494                         break;
2495                 }
2496         }
2497         return offset;
2498
2499 }
2500
2501 static guint
2502 fPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 tagoffset)
2503 {
2504         guint lastoffset = offset;
2505         proto_item *tt;
2506         proto_tree *subtree;
2507         guint8 tag_no, tag_info;
2508         guint32 lvt;
2509         
2510         offset = fPropertyReference(tvb, tree, offset, tagoffset, 0);
2511         if (offset > lastoffset)
2512         {
2513                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2514                 if (tag_no == tagoffset+2) {  /* Value - might not be present in ReadAccessResult */
2515                         if (tag_is_opening(tag_info)) {
2516                                 tt = proto_tree_add_text(tree, tvb, offset, 1, "propertyValue");
2517                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2518                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2519                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2520                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2521                         }
2522                 }
2523         }
2524         return offset;
2525 }
2526
2527 static guint
2528 fBACnetPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
2529 {
2530         guint lastoffset = 0;
2531         guint8 tag_no, tag_info;
2532         guint32 lvt;
2533
2534         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2535                 lastoffset = offset;
2536                 offset = fPropertyValue(tvb, tree, offset, 0);
2537                 if (offset > lastoffset)
2538                 {
2539                         /* detect optional priority
2540                         by looking to see if the next tag is context tag number 3 */
2541                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2542                         if (tag_is_context_specific(tag_info) && (tag_no == 3))
2543                                 offset = fUnsignedTag (tvb,tree,offset,"Priority: ");
2544                 }
2545         }
2546         return offset;
2547 }
2548
2549 static guint
2550 fSubscribeCOVPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2551 {
2552         guint lastoffset = 0;
2553
2554         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2555                 lastoffset = offset;
2556         
2557                 switch (fTagNo(tvb,offset)) {
2558                 case 0: /* ProcessId */
2559                         offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
2560                         break;
2561                 case 1: /* monitored ObjectId */
2562                         offset = fObjectIdentifier (tvb, tree, offset);
2563                         break;
2564                 case 2: /* issueConfirmedNotifications */
2565                         offset = fBooleanTag (tvb, tree, offset, "issue Confirmed Notifications: ");
2566                         break;
2567                 case 3: /* life time */
2568                         offset = fTimeSpan (tvb,tree,offset,"life time");
2569                         break;
2570                 case 4: /* monitoredPropertyIdentifier */
2571                         offset = fBACnetPropertyReference (tvb, tree, offset, 0);
2572                         break;
2573                 case 5: /* covIncrement */
2574                         offset = fRealTag (tvb, tree, offset, "COV Increment: ");
2575                         break;
2576                 default:
2577                         return offset;
2578                         break;
2579                 }
2580         }
2581         return offset;
2582 }
2583
2584 static guint
2585 fSubscribeCOVRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2586 {
2587         return fSubscribeCOVPropertyRequest(tvb, tree, offset);
2588 }
2589
2590 static guint
2591 fWhoHas (tvbuff_t *tvb, proto_tree *tree, guint offset)
2592 {
2593         guint lastoffset = 0;
2594
2595         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2596                 lastoffset = offset;
2597         
2598                 switch (fTagNo(tvb, offset)) {
2599                 case 0: /* deviceInstanceLowLimit */
2600                         offset = fUnsignedTag (tvb, tree, offset, "device Instance Low Limit: ");
2601                         break;
2602                 case 1: /* deviceInstanceHighLimit */
2603                         offset = fUnsignedTag (tvb, tree, offset, "device Instance High Limit: ");
2604                         break;
2605                 case 2: /* BACnetObjectId */
2606                         offset = fObjectIdentifier (tvb, tree, offset);
2607                 break;
2608                 case 3: /* messageText */
2609                         offset = fCharacterString (tvb,tree,offset, "Object Name: ");
2610                         break;
2611                 default:
2612                         return offset;
2613                 }
2614         }
2615         return offset;
2616 }
2617
2618
2619 static guint
2620 fDailySchedule (tvbuff_t *tvb, proto_tree *subtree, guint offset)
2621 {
2622         guint lastoffset = 0;
2623         guint8 tag_no, tag_info;
2624         guint32 lvt;
2625         
2626         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2627                 lastoffset = offset;
2628                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2629                 if (tag_is_closing(tag_info)) {
2630                         offset += fTagHeaderTree (tvb, subtree, offset,
2631                                 &tag_no, &tag_info, &lvt);
2632                         return offset;
2633                 }
2634                 
2635                 switch (tag_no) {
2636                 case 0: /* day-schedule */
2637                         if (tag_is_opening(tag_info)) {
2638                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2639                                 offset = fTimeValue (tvb, subtree, offset);
2640                                 break;
2641                         }
2642                         FAULT;
2643                         break;
2644                 default:
2645                         return offset;
2646                 }
2647         }
2648         return offset;
2649 }
2650
2651 static guint
2652 fWeeklySchedule (tvbuff_t *tvb, proto_tree *tree, guint offset)
2653 {
2654         guint lastoffset = 0;
2655         guint8 tag_no, tag_info;
2656         guint32 lvt;
2657         guint i=1;
2658         proto_tree *subtree = tree;
2659         proto_item *tt;
2660         
2661         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2662                 lastoffset = offset;
2663                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2664                 if (tag_is_closing(tag_info)) {
2665                         offset += fTagHeaderTree (tvb, tree, offset,
2666                                 &tag_no, &tag_info, &lvt);
2667                         return offset;
2668                 }
2669                 tt = proto_tree_add_text(tree, tvb, offset, 0, val_to_str(i++, days, "day of week (%d) not found"));
2670                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2671                 offset = fDailySchedule (tvb,subtree,offset);
2672         }
2673         return offset;
2674 }
2675
2676
2677 static guint
2678 fUTCTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
2679 {
2680         if (tvb_length_remaining(tvb, offset) <= 0)
2681                 return offset;
2682         
2683         return fDateTime (tvb, tree, offset, "UTC-Time: ");
2684 }
2685
2686 static guint
2687 fTimeSynchronizationRequest  (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, NULL);
2693 }
2694
2695 static guint
2696 fDateRange  (tvbuff_t *tvb, proto_tree *tree, guint offset)
2697 {
2698         if (tvb_length_remaining(tvb, offset) <= 0)
2699                 return offset;
2700     offset = fDate (tvb,tree,offset,"Start Date: ");
2701         return fDate (tvb, tree, offset, "End Date: ");
2702 }
2703
2704 static guint
2705 fConfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2706 {
2707         guint lastoffset = 0;
2708
2709         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2710                 lastoffset = offset;
2711                 switch (fTagNo(tvb, offset)) {
2712
2713                 case 0: /* textMessageSourceDevice */
2714                         offset = fObjectIdentifier (tvb, tree, offset);
2715                         break;
2716                 case 1: /* messageClass */
2717                         switch (fTagNo(tvb, offset)) {
2718                         case 0: /* numeric */
2719                                 offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
2720                                 break;
2721                         case 1: /* character */
2722                                 offset = fCharacterString (tvb, tree, offset, "message Class: ");
2723                                 break;
2724                         }
2725                         break;
2726                 case 2: /* messagePriority */
2727                         offset = fEnumeratedTag (tvb, tree, offset, "message Priority: ",
2728                                 BACnetMessagePriority);
2729                         break;
2730                 case 3: /* message */
2731                         offset = fCharacterString (tvb, tree, offset, "message: ");
2732                         break;
2733                 default:
2734                         return offset;
2735                         break;  
2736                 }
2737         }
2738         return offset;
2739 }
2740
2741 static guint
2742 fUnconfirmedTextMessageRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2743 {
2744         return fConfirmedTextMessageRequest(tvb, tree, offset);
2745 }
2746
2747 static guint
2748 fConfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2749 {
2750         guint lastoffset = 0;
2751         guint8 tag_no, tag_info;
2752         guint32 lvt;
2753         proto_tree *subtree = tree;
2754         proto_item *tt;
2755
2756         /* exit loop if nothing happens inside */ 
2757         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  
2758                 lastoffset = offset;
2759                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2760                 if (tag_is_closing(tag_info)) {
2761                         if (tag_no == 2) /* Make sure it's the expected tag */
2762                         {
2763                                 offset += fTagHeaderTree (tvb, subtree, offset,
2764                                         &tag_no, &tag_info, &lvt);
2765                                 subtree = tree;
2766                                 continue;
2767                         }
2768                         else
2769                         {
2770                                 break; /* End loop if incorrect closing tag */
2771                         }
2772                 }
2773                 switch (tag_no) {
2774
2775                 case 0: /* vendorID */
2776                         offset = fUnsignedTag (tvb, subtree, offset, "vendor ID: ");
2777                         break;
2778                 case 1: /* serviceNumber */
2779                         offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
2780                         break;
2781                 case 2: /*serviceParameters */
2782                         if (tag_is_opening(tag_info)) {
2783                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
2784                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2785                                 propertyIdentifier = -1;
2786                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
2787                                 break;
2788                         }
2789                         FAULT;
2790                         break;
2791                 default:
2792                         return offset;
2793                 }
2794         }
2795         return offset;
2796 }
2797
2798 static guint
2799 fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
2800 {
2801         return fConfirmedPrivateTransferRequest(tvb, tree, offset);
2802 }
2803
2804 static guint
2805 fConfirmedPrivateTransferAck(tvbuff_t *tvb, proto_tree *tree, guint offset)
2806 {
2807         return fConfirmedPrivateTransferRequest(tvb, tree, offset);
2808 }
2809
2810 static guint
2811 fLifeSafetyOperationRequest(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
2812 {
2813         guint lastoffset = 0;
2814         guint8 tag_no, tag_info;
2815         guint32 lvt;
2816         proto_tree *subtree = tree;
2817         proto_item *tt;
2818
2819         if (label != NULL) {
2820                 tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", label);
2821                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2822         }
2823
2824         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2825                 lastoffset = offset;
2826                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
2827         
2828                 switch (tag_no) {
2829                 case 0: /* subscriberProcessId */
2830                         offset = fUnsignedTag (tvb, subtree, offset, "requesting Process Id: ");
2831                         break;
2832                 case 1: /* requestingSource */
2833                         offset = fCharacterString (tvb, tree, offset, "requesting Source: ");
2834                         break;
2835                 case 2: /* request */
2836                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
2837                                 "request: ", BACnetLifeSafetyOperation, 64);
2838                         break;
2839                 case 3: /* objectId */
2840                         offset = fObjectIdentifier (tvb, subtree, offset);
2841                         break;
2842                 default:
2843                         return offset;
2844                         break;
2845                 }
2846         }
2847         return offset;
2848 }
2849
2850 static guint fBACnetPropertyStates(tvbuff_t *tvb, proto_tree *tree, guint offset)
2851 {
2852         switch (fTagNo(tvb, offset))
2853         {
2854         case 0:
2855                 offset = fBooleanTag (tvb, tree, offset, "boolean-value: ");
2856                 break;
2857         case 1:
2858                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2859                         "binary-value: ", BACnetBinaryPV, 2);
2860                 break;
2861         case 2:
2862                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2863                         "event-type: ", BACnetEventType, 12);
2864                 break;
2865         case 3:
2866                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2867                         "polarity: ", BACnetPolarity, 2);
2868                 break;
2869         case 4:
2870                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2871                         "program-change: ", BACnetProgramRequest, 5);
2872                 break;
2873         case 5:
2874                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2875                         "program-state: ", BACnetProgramState, 5);
2876                 break;
2877         case 6:
2878                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2879                         "reason-for-halt: ", BACnetProgramError, 5);
2880                 break;
2881         case 7:
2882                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2883                         "reliability: ", BACnetReliability, 10);
2884                 break;
2885         case 8:
2886                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2887                         "state: ", BACnetEventState, 64);
2888                 break;
2889         case 9:
2890                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2891                         "system-status: ", BACnetDeviceStatus, 64);
2892                 break;
2893         case 10:
2894                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2895                         "units: ", BACnetEngineeringUnits, 2);
2896                 break;
2897         case 11:
2898                 offset = fUnsignedTag(tvb, tree, offset, "unsigned-value: ");
2899                 break;
2900         case 12:
2901                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2902                         "life-safety-mode: ", BACnetLifeSafetyMode, 64);
2903                 break;
2904         case 13:
2905                 offset = fEnumeratedTagSplit (tvb, tree, offset, 
2906                         "life-safety-state: ", BACnetLifeSafetyState, 64);
2907                 break;
2908         default:
2909                 break;
2910         }
2911         return offset;
2912 }
2913
2914 static guint
2915 fNotificationParameters (tvbuff_t *tvb, proto_tree *tree, guint offset)
2916 {
2917         guint lastoffset = offset;
2918         guint8 tag_no, tag_info;
2919         guint32 lvt;
2920         proto_tree *subtree = tree;
2921         proto_item *tt;
2922
2923         tt = proto_tree_add_text(subtree, tvb, offset, 0, "notification parameters");
2924         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
2925         /* Opeing tag for parameter choice */
2926         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2927
2928         switch (tag_no) {
2929         case 0: /* change-of-bitstring */
2930                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2931                 lastoffset = offset;
2932                         switch (fTagNo(tvb, offset)) {
2933                         case 0:
2934                                 offset = fBitStringTag (tvb, subtree, offset, 
2935                                         "referenced-bitstring: ");
2936                                 break;
2937                         case 1:
2938                                 offset = fEnumeratedTag (tvb, subtree, offset, 
2939                                         "status-flags: ", BACnetStatusFlags);
2940                                 break;
2941                         default:
2942                                 return offset;
2943                                 break;
2944                         }
2945                 }
2946                 break;
2947         case 1: /* change-of-state */
2948                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2949                 lastoffset = offset;
2950                         switch (fTagNo(tvb, offset)) {
2951                         case 0:
2952                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2953                                 offset = fBACnetPropertyStates(tvb, subtree, offset);
2954                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2955                         case 1:
2956                                 offset = fEnumeratedTag (tvb, subtree, offset, 
2957                                         "status-flags: ", BACnetStatusFlags);
2958                         lastoffset = offset;
2959                                 break;
2960                         default:
2961                                 break;
2962                         }
2963                 }
2964                 break;
2965     case 2: /* change-of-value */
2966                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2967                 lastoffset = offset;
2968                         switch (fTagNo(tvb, offset)) {
2969                         case 0:
2970                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2971                                 switch (fTagNo(tvb, offset)) {
2972                                 case 0:
2973                                         offset = fBitStringTag (tvb, subtree, offset, 
2974                                                 "changed-bits: ");
2975                                         break;
2976                                 case 1:
2977                                         offset = fRealTag (tvb, subtree, offset, 
2978                                                 "changed-value: ");
2979                                         break;
2980                                 default:
2981                                         break;
2982                                 }
2983                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
2984                                 break;
2985                         case 1:
2986                                 offset = fEnumeratedTag (tvb, subtree, offset, 
2987                                         "status-flags: ", BACnetStatusFlags);
2988                                 break;
2989                         default:
2990                                 break;
2991                         }
2992                 }
2993                 break;
2994     case 3: /* command-failure */
2995                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
2996                 lastoffset = offset;
2997                         switch (fTagNo(tvb, offset)) {
2998                         case 0: /* "command-value: " */
2999                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3000                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3001                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3002                                 break;
3003                         case 1:
3004                                 offset = fEnumeratedTag (tvb, subtree, offset, 
3005                                         "status-flags: ", BACnetStatusFlags);
3006                         case 2: /* "feedback-value: " */
3007                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3008                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3009                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3010                         default:
3011                                 break;
3012                         }
3013                 }
3014                 break;
3015     case 4: /* floating-limit */
3016                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3017                 lastoffset = offset;
3018                         switch (fTagNo(tvb, offset)) {
3019                         case 0:
3020                                 offset = fRealTag (tvb, subtree, offset, "reference-value: ");
3021                                 break;
3022                         case 1:
3023                                 offset = fEnumeratedTag (tvb, subtree, offset, 
3024                                         "status-flags: ", BACnetStatusFlags);
3025                                 break;
3026                         case 2:
3027                                 offset = fRealTag (tvb, subtree, offset, "setpoint-value: ");
3028                                 break;
3029                         case 3:
3030                                 offset = fRealTag (tvb, subtree, offset, "error-limit: ");
3031                         default:
3032                                 break;
3033                         }
3034                 }
3035                 break;
3036     case 5: /* out-of-range */
3037                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3038                 lastoffset = offset;
3039                         switch (fTagNo(tvb, offset)) {
3040                         case 0:
3041                                 offset = fRealTag (tvb, subtree, offset, "exceeding-value: ");
3042                                 break;
3043                         case 1:
3044                                 offset = fEnumeratedTag (tvb, subtree, offset, 
3045                                         "status-flags: ", BACnetStatusFlags);
3046                                 break;
3047                         case 2:
3048                                 offset = fRealTag (tvb, subtree, offset, "deadband: ");
3049                                 break;
3050                         case 3:
3051                                 offset = fRealTag (tvb, subtree, offset, "exceeded-limit: ");
3052                         default:
3053                                 break;
3054                         }
3055                 }
3056             break;
3057         case 6:
3058                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3059                 lastoffset = offset;
3060                         offset =fBACnetPropertyValue (tvb,subtree,offset);
3061                 }
3062                 break;
3063         case 7: /* buffer-ready */
3064                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3065                 lastoffset = offset;
3066                         switch (fTagNo(tvb, offset)) {
3067                         case 0:
3068                                 offset = fObjectIdentifier (tvb, subtree, offset); /* buffer-device */
3069                                 break;
3070                         case 1:
3071                                 offset = fObjectIdentifier (tvb, subtree, offset); /* buffer-object */
3072                                 break;
3073                         case 2:
3074                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3075                                 offset = fDateTime (tvb, subtree, offset, "previous-notification: ");
3076                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3077                                 break;
3078                         case 3:
3079                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3080                                 offset = fDateTime (tvb, subtree, offset, "current-notification: ");
3081                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3082                         default:
3083                                 break;
3084                         }
3085                 }
3086                 break;
3087     case 8: /* change-of-life-safety */
3088                 while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3089                 lastoffset = offset;
3090                         switch (fTagNo(tvb, offset)) {
3091                         case 0:
3092                                 offset = fEnumeratedTagSplit (tvb, subtree, offset, 
3093                                         "new-state: ", BACnetLifeSafetyState, 256);
3094                                 break;
3095                         case 1:
3096                                 offset = fEnumeratedTagSplit (tvb, subtree, offset, 
3097                                         "new-mode: ", BACnetLifeSafetyState, 256);
3098                                 break;
3099                         case 2:
3100                                 offset = fEnumeratedTag (tvb, subtree, offset, 
3101                                         "status-flags: ", BACnetStatusFlags);
3102                         case 3:
3103                                 offset = fEnumeratedTagSplit (tvb, subtree, offset, 
3104                                         "operation-expected: ", BACnetLifeSafetyOperation, 64);
3105                         default:
3106                                 return offset;
3107                                 break;
3108                         }
3109                 }
3110             break;
3111         default:
3112                 break;
3113         }
3114         /* Closing tag for parameter choice */
3115         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3116
3117         return offset;
3118 }
3119
3120 #if 0
3121 static guint
3122 fEventParameter (tvbuff_t *tvb, proto_tree *tree, guint offset)
3123 {
3124         guint lastoffset = 0;
3125
3126         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3127                 lastoffset = offset;
3128                 switch (fTagNo(tvb, offset)) {
3129                 case 0: /* change-of-bitstring */
3130                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3131                                 lastoffset = offset;
3132                                 switch (fTagNo(tvb, offset)) {
3133                                 case 0:
3134                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3135                                         break;
3136                                 case 1:
3137                                         offset = fBitStringTag (tvb, tree, offset, "bitmask: ");
3138                                         break;
3139                                 case 2: /* SEQUENCE OF BIT STRING */
3140                                         offset = fBitStringTagVS (tvb, tree, offset,
3141                                                 "bitstring value: ", BACnetEventTransitionBits);
3142                                         break;
3143                                 default:
3144                                         return offset;
3145                                 }
3146                         }
3147         break;
3148                 case 1: /* change-of-state */
3149                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3150                         lastoffset = offset;
3151                                 switch (fTagNo(tvb, offset)) {
3152                                 case 0:
3153                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3154                                         break;
3155                                 case 1: /* SEQUENCE OF BACnetPropertyStates */
3156                                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3157                                                 "value: ", BACnetPropertyStates, 64);
3158                                         break;
3159                                 default:
3160                                         return offset;
3161                                 }
3162                         }
3163                         break;
3164         case 2: /* change-of-value */
3165                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3166                         lastoffset = offset;
3167                                 switch (fTagNo(tvb, offset)) {
3168                                 case 0:
3169                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3170                                         break;
3171                                 case 1: /* don't loop it, it's a CHOICE */
3172                                         switch (fTagNo(tvb, offset)) {
3173                                         case 0:
3174                                                 offset = fBitStringTag (tvb, tree, offset, "bitmask: ");
3175                                                 break;
3176                                         case 1:
3177                                                 offset = fRealTag (tvb, tree, offset, 
3178                                                         "referenced Property Increment: ");
3179                                                 break;
3180                                         default:
3181                                                 return offset;
3182                                         }
3183                                 default:
3184                                         return offset;
3185                                 }
3186                         }
3187                 break;
3188         case 3: /* command-failure */
3189                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3190                         lastoffset = offset;
3191                                 switch (fTagNo(tvb, offset)) {
3192                                 case 0:
3193                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3194                                         break;
3195                                 case 1:
3196                                         offset = fDeviceObjectPropertyReference (tvb,tree,offset);
3197                                 default:
3198                                         return offset;
3199                                 }
3200                         }
3201         break;
3202         case 4: /* floating-limit */
3203                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3204                         lastoffset = offset;
3205                                 switch (fTagNo(tvb, offset)) {
3206                                 case 0:
3207                                         offset = fTimeSpan   (tvb, tree, offset, "Time Delay");
3208                                         break;
3209                                 case 1:
3210                                         offset = fDeviceObjectPropertyReference (tvb,tree,offset);
3211                                         break;
3212                                 case 2:
3213                                         offset = fRealTag (tvb, tree, offset, "low diff limit: ");
3214                                         break;
3215                                 case 3:
3216                                         offset = fRealTag (tvb, tree, offset, "high diff limit: ");
3217                                         break;
3218                                 case 4:
3219                                         offset = fRealTag (tvb, tree, offset, "deadband: ");
3220                                         break;
3221                                 default:
3222                                         return offset;
3223                                 }
3224                         }
3225                         break;
3226                 case 5: /* out-of-range */
3227                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3228                                 lastoffset = offset;
3229                                 switch (fTagNo(tvb, offset)) {
3230                                 case 0:
3231                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3232                                         break;
3233                                 case 1:
3234                                         offset = fRealTag (tvb, tree, offset, "low limit: ");
3235                                         break;
3236                                 case 2:
3237                                         offset = fRealTag (tvb, tree, offset, "high limit: ");
3238                                         break;
3239                                 case 3:
3240                                         offset = fRealTag (tvb, tree, offset, "deadband: ");
3241                                         break;
3242                                 default:
3243                                         return offset;
3244                                 }
3245                         }
3246         break;
3247                 case 6:
3248                         offset = fBACnetPropertyValue (tvb,tree,offset);
3249                         break;
3250                 case 7: /* buffer-ready */
3251                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3252                                 lastoffset = offset;
3253                                 switch (fTagNo(tvb, offset)) {
3254                                 case 0:
3255                                         offset = fUnsignedTag (tvb,tree,offset,"notification threshold");
3256                                         break;
3257                                 case 1:
3258                                         offset = fUnsignedTag (tvb,tree,offset,
3259                                                 "previous notification count: ");
3260                                         break;
3261                                 default:
3262                                         return offset;
3263                                 }
3264                         }
3265         break;
3266                 case 8: /* change-of-life-safety */
3267                         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3268                                 lastoffset = offset;
3269                                 switch (fTagNo(tvb, offset)) {
3270                                 case 0:
3271                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
3272                                         break;
3273                                 case 1:
3274                                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3275                                                 "life safety alarm value: ", BACnetLifeSafetyState, 256);
3276                                         break;
3277                                 case 2:
3278                                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3279                                                 "alarm value: ", BACnetLifeSafetyState, 256);
3280                                         break;
3281                                 case 3:
3282                                         offset = fDeviceObjectPropertyReference (tvb, tree, offset);
3283                                         break;
3284                                 default:
3285                                         return offset;
3286                                 }
3287                         }
3288                         break;
3289                 default:
3290                         return offset;
3291                 }
3292         }
3293         return offset;
3294 }
3295
3296 static guint
3297 fLogRecord (tvbuff_t *tvb, proto_tree *tree, guint offset)
3298 {
3299         guint lastoffset = 0;
3300
3301         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3302                 lastoffset = offset;
3303                 switch (fTagNo(tvb, offset)) {
3304                 case 0: /* timestamp */
3305                         offset = fDateTime (tvb,tree,offset,NULL);
3306                         break;
3307                 case 1: /* logDatum: don't loop, it's a CHOICE */
3308                         switch (fTagNo(tvb, offset)) {
3309                         case 0: /* logStatus */
3310                                 offset = fEnumeratedTag (tvb, tree, offset, 
3311                                         "log status: ", BACnetLogStatus);
3312                                 break;
3313                         case 1:
3314                                 offset = fBooleanTag (tvb, tree, offset, "boolean-value: ");
3315                                 break;
3316                         case 2:
3317                                 offset = fRealTag (tvb, tree, offset, "real value: ");
3318                                 break;
3319                         case 3:
3320                                 offset = fUnsignedTag (tvb, tree, offset, "enum value: ");
3321                                 break;
3322                         case 4:
3323                                 offset = fUnsignedTag (tvb, tree, offset, "unsigned value: ");
3324                                 break;
3325                         case 5:
3326                                 offset = fSignedTag (tvb, tree, offset, "signed value: ");
3327                                 break;
3328                         case 6:
3329                                 offset = fBitStringTag (tvb, tree, offset, "bitstring value: ");
3330                                 break;
3331                         case 7:
3332                                 offset = fNullTag(tvb, tree, offset, "null value: ");
3333                                 break;
3334                         case 8:
3335                                 offset = fError (tvb,tree,offset);
3336                                 break;
3337                         case 9:
3338                                 offset = fRealTag (tvb, tree, offset, "time change: ");
3339                                 break;
3340                         case 10:        /* any Value */
3341                                 offset = fAbstractSyntaxNType (tvb, tree, offset);
3342                                 break;
3343                         default:
3344                                 return offset;
3345                         }
3346         break;
3347                 case 2:
3348                         offset = fEnumeratedTag (tvb, tree, offset, 
3349                                 "status Flags: ", BACnetStatusFlags);
3350                         break;
3351                 default:
3352                         return offset;
3353                 }
3354         }
3355         return offset;
3356 }
3357 #endif
3358
3359 static guint
3360 fConfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3361 {
3362         guint lastoffset = 0;
3363         guint8 tag_no, tag_info;
3364         guint32 lvt;
3365
3366         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3367                 lastoffset = offset;
3368         
3369                 switch (fTagNo(tvb,offset)) {
3370                 case 0: /* ProcessId */
3371                         offset = fProcessId (tvb,tree,offset);
3372                         break;
3373                 case 1: /* initiating ObjectId */
3374                         offset = fObjectIdentifier (tvb, tree, offset);
3375                         break;
3376                 case 2: /* event ObjectId */
3377                         offset = fObjectIdentifier (tvb, tree, offset);
3378                         break;
3379                 case 3: /* time stamp */
3380                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3381                         offset = fTimeStamp (tvb, tree, offset);
3382                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3383                         break;
3384                 case 4: /* notificationClass */
3385                         offset = fUnsignedTag (tvb, tree, offset, "Notification Class: ");
3386                         break;
3387                 case 5: /* Priority */
3388                         offset = fUnsignedTag (tvb, tree, offset, "Priority: ");
3389                         break;
3390                 case 6: /* EventType */
3391                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3392                                 "Event Type: ", BACnetEventType, 64);
3393                         break;
3394                 case 7: /* messageText */
3395                         offset = fCharacterString (tvb, tree, offset, "message Text: ");
3396                         break;
3397                 case 8: /* NotifyType */
3398                         offset = fEnumeratedTag (tvb, tree, offset,
3399                                 "Notify Type: ", BACnetNotifyType);
3400                         break;
3401                 case 9: /* ackRequired */
3402                         offset = fBooleanTag (tvb, tree, offset, "ack Required: ");
3403                         break;
3404                 case 10: /* fromState */
3405                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3406                                 "from State: ", BACnetEventState, 64);
3407                         break;
3408                 case 11: /* toState */
3409                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3410                                 "to State: ", BACnetEventState, 64);
3411                         break;
3412                 case 12: /* NotificationParameters */
3413                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3414                         offset = fNotificationParameters (tvb, tree, offset);
3415                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3416                         break;
3417                 default:
3418                         break;
3419                 }
3420         }
3421         return offset;
3422 }
3423
3424 static guint
3425 fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3426 {
3427         return fConfirmedEventNotificationRequest (tvb, tree, offset);
3428 }
3429
3430 static guint
3431 fConfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3432 {
3433         guint lastoffset = 0;
3434         guint8 tag_no, tag_info;
3435         guint32 lvt;
3436         proto_tree *subtree = tree;
3437         proto_item *tt;
3438
3439         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3440                 lastoffset = offset;
3441                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
3442                 if (tag_is_closing(tag_info)) {   
3443                         offset += fTagHeaderTree (tvb, subtree, offset,
3444                                 &tag_no, &tag_info, &lvt);
3445                         subtree = tree;
3446                         continue;
3447                 }
3448         
3449                 switch (tag_no) {
3450                 case 0: /* ProcessId */
3451                         offset = fProcessId (tvb,tree,offset);
3452                         break;
3453                 case 1: /* initiating ObjectId */
3454                         offset = fObjectIdentifier (tvb, subtree, offset);
3455                         break;
3456                 case 2: /* monitored ObjectId */
3457                         offset = fObjectIdentifier (tvb, subtree, offset);
3458                         break;
3459                 case 3: /* time remaining */
3460                         offset = fTimeSpan (tvb, tree, offset, "Time remaining");
3461                         break;
3462                 case 4: /* List of Values */
3463                         if (tag_is_opening(tag_info)) {
3464                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
3465                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
3466                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3467                                 offset = fBACnetPropertyValue (tvb, subtree, offset);
3468                                 break;
3469                         }
3470                         FAULT;
3471                         break;
3472                 default:
3473                         return offset;
3474                         break;
3475                 }
3476         }
3477         return offset;
3478 }
3479
3480 static guint
3481 fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3482 {
3483         return fConfirmedCOVNotificationRequest (tvb, tree, offset);
3484 }
3485
3486 static guint
3487 fAcknowlegdeAlarmRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3488 {
3489         guint lastoffset = 0;
3490
3491         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3492                 lastoffset = offset;
3493                 switch (fTagNo(tvb, offset)) {
3494                 case 0: /* acknowledgingProcessId */
3495                         offset = fUnsignedTag (tvb, tree, offset, "acknowledging Process Id: ");
3496                         break;
3497                 case 1: /* eventObjectId */
3498                         offset = fObjectIdentifier (tvb, tree, offset);
3499                         break;
3500                 case 2: /* eventStateAcknowledged */
3501                         offset = fEnumeratedTagSplit (tvb, tree, offset, 
3502                                 "event State Acknowledged: ", BACnetEventState, 64);
3503                         break;
3504                 case 3: /* timeStamp */
3505                         offset = fTime (tvb, tree, offset, "time Stamp: ");
3506                         break;
3507                 case 4: /* acknowledgementSource */
3508                         offset = fCharacterString (tvb, tree, offset, "acknowledgement Source: ");
3509                         break;
3510                 case 5: /* timeOfAcknowledgement */
3511                         offset = fTime (tvb, tree, offset, "time Of Acknowledgement: ");
3512                         break;
3513                 default:
3514                         return offset;
3515                         break;
3516                 }
3517         }
3518         return offset;
3519 }
3520
3521 static guint
3522 fGetAlarmSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3523 {
3524         guint lastoffset = 0;
3525
3526         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3527                 lastoffset = offset;
3528                 offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: ");
3529                 offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, 
3530                         "alarm State: ", BACnetEventState, 64);
3531                 offset = fApplicationTypesEnumerated (tvb, tree, offset, 
3532                         "acknowledged Transitions: ", BACnetEventTransitionBits);
3533         }
3534         return  offset;
3535 }
3536
3537 static guint
3538 fGetEnrollmentSummaryRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3539 {
3540         guint lastoffset = 0;
3541         guint8 tag_no, tag_info;
3542         guint32 lvt;
3543
3544         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3545                 lastoffset = offset;
3546                 switch (fTagNo(tvb, offset)) {
3547                 case 0: /* acknowledgmentFilter */
3548                         offset = fEnumeratedTag (tvb, tree, offset, 
3549                                 "acknowledgment Filter: ", BACnetAcknowledgementFilter);
3550                         break;
3551                 case 1: /* eventObjectId */
3552                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3553                         offset = fRecipientProcess (tvb, tree, offset);
3554                         break;
3555                 case 2: /* eventStateFilter */
3556                         offset = fEnumeratedTag (tvb, tree, offset, 
3557                                 "event State Filter: ", BACnetEventStateFilter);
3558                         break;
3559                 case 3: /* eventTypeFilter */
3560                         offset = fEnumeratedTag (tvb, tree, offset, 
3561                                 "event Type Filter: ", BACnetEventType);
3562                         break;
3563                 case 4: /* priorityFilter */
3564                         offset = fUnsignedTag (tvb, tree, offset, "min Priority: ");
3565                         offset = fUnsignedTag (tvb, tree, offset, "max Priority: ");
3566                         break;
3567                 case 5: /* notificationClassFilter */
3568                         offset = fUnsignedTag (tvb, tree, offset, "notification Class Filter: ");
3569                         break;
3570                 default:
3571                         return offset;
3572                         break;
3573                 }
3574         }
3575         return offset;
3576 }
3577
3578 static guint
3579 fGetEnrollmentSummaryAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3580 {
3581         guint lastoffset = 0;
3582
3583         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3584                 lastoffset = offset;
3585                 offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: ");
3586                 offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, 
3587                         "event Type: ", BACnetEventType, 64);
3588                 offset = fApplicationTypesEnumerated (tvb, tree, offset, 
3589                         "event State: ", BACnetEventStateFilter);
3590                 offset = fApplicationTypes (tvb, tree, offset, "Priority: ");
3591                 offset = fApplicationTypes (tvb, tree, offset, "Notification Class: ");
3592         }
3593
3594         return  offset;
3595 }
3596
3597 static guint
3598 fGetEventInformationRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3599 {
3600         guint lastoffset = 0;
3601
3602         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3603                 lastoffset = offset;
3604                 switch (fTagNo(tvb, offset)) {
3605                 case 0: /* lastReceivedObjectId */
3606                         offset = fObjectIdentifier (tvb, tree, offset);
3607                         break;
3608                 default:
3609                         return offset;
3610                         break;
3611                 }
3612         }
3613         return offset;
3614 }
3615
3616 static guint
3617 flistOfEventSummaries (tvbuff_t *tvb, proto_tree *tree, guint offset)
3618 {
3619         guint lastoffset = 0;
3620
3621         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3622                 lastoffset = offset;
3623                 switch (fTagNo(tvb, offset)) {
3624                 case 0: /* ObjectId */
3625                         offset = fObjectIdentifier (tvb, tree, offset);
3626                         break;
3627                 case 1: /* eventState */
3628                         offset = fEnumeratedTag (tvb, tree, offset, 
3629                                 "event State: ", BACnetEventStateFilter);
3630                         break;
3631                 case 2: /* acknowledgedTransitions */
3632                         offset = fEnumeratedTag (tvb, tree, offset, 
3633                                 "acknowledged Transitions: ", BACnetEventTransitionBits);
3634                         break;
3635                 case 3: /* eventTimeStamps */
3636                         offset = fTime (tvb, tree, offset, "time Stamp: ");
3637                         offset = fTime (tvb, tree, offset, "time Stamp: ");
3638                         offset = fTime (tvb, tree, offset, "time Stamp: ");
3639                         break;
3640                 case 4: /* notifyType */
3641                         offset = fEnumeratedTag (tvb, tree, offset, 
3642                                 "Notify Type: ", BACnetNotifyType);
3643                         break;
3644                 case 5: /* eventEnable */
3645                         offset = fEnumeratedTag (tvb, tree, offset, 
3646                                 "event Enable: ", BACnetEventTransitionBits);
3647                         break;
3648                 case 6: /* eventPriorities */
3649                         offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
3650                         offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
3651                         offset = fUnsignedTag (tvb, tree, offset, "event Priority: ");
3652                         break;
3653                 default:
3654                         return offset;
3655                         break;
3656                 }
3657         }
3658         return offset;
3659 }
3660
3661 static guint
3662 fGetEventInformationACK (tvbuff_t *tvb, proto_tree *tree, guint offset)
3663 {
3664         guint lastoffset = 0;
3665         guint8 tag_no, tag_info;
3666         guint32 lvt;
3667
3668         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3669                 lastoffset = offset;
3670                 switch (fTagNo(tvb, offset)) {
3671                 case 0: /* listOfEventSummaries */
3672                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
3673                         offset = flistOfEventSummaries (tvb, tree, offset);
3674                         break;
3675                 case 1: /* moreEvents */
3676                         offset = fBooleanTag (tvb, tree, offset, "more Events: ");
3677                         break;
3678                 default:
3679                         return offset;
3680                         break;
3681                 }
3682         }
3683         return offset;
3684 }
3685
3686 static guint
3687 fAddListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3688 {
3689         guint lastoffset = 0;
3690         guint8 tag_no, tag_info;
3691         guint32 lvt;
3692         proto_tree *subtree = tree;
3693         proto_item *tt;
3694
3695         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3696                 lastoffset = offset;
3697                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
3698                 if (tag_is_closing(tag_info)) {
3699                         offset += fTagHeaderTree (tvb, subtree, offset,
3700                                 &tag_no, &tag_info, &lvt);
3701                         subtree = tree;
3702                         continue;
3703                 }
3704         
3705                 switch (tag_no) {
3706                 case 0: /* ObjectId */
3707                         offset = fBACnetObjectPropertyReference (tvb, subtree, offset);
3708                         break;
3709                 case 3: /* listOfElements */
3710                         if (tag_is_opening(tag_info)) {
3711                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfElements");
3712                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
3713                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3714                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3715                                 break;
3716                         }
3717                         FAULT;
3718                         break;
3719                 default:
3720                         return offset;
3721                         break;
3722                 }
3723         }
3724         return offset;
3725 }
3726
3727 static guint
3728 fDeleteObjectRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3729 {
3730         return fObjectIdentifier (tvb, tree, offset);
3731 }
3732
3733 static guint
3734 fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3735 {
3736         guint lastoffset = 0;
3737
3738         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3739                 lastoffset = offset;
3740         
3741                 switch (fTagNo(tvb, offset)) {
3742                 case 0: /* timeDuration */
3743                         offset = fUnsignedTag (tvb,tree,offset,"time Duration: ");
3744                         break;
3745                 case 1: /* enable-disable */
3746                         offset = fEnumeratedTag (tvb, tree, offset, "enable-disable: ",
3747                                 BACnetEnableDisable);
3748                         break;
3749                 case 2: /* password */
3750                         offset = fCharacterString (tvb, tree, offset, "Password: ");
3751                         break;
3752                 default:
3753                         return offset;
3754                         break;
3755                 }
3756         }
3757         return offset;
3758 }
3759
3760 static guint
3761 fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3762 {
3763         guint lastoffset = 0;
3764
3765         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3766                 lastoffset = offset;
3767         
3768                 switch (fTagNo(tvb, offset)) {
3769                 case 0: /* reinitializedStateOfDevice */
3770                         offset = fEnumeratedTag (tvb, tree, offset, 
3771                                 "reinitialized State Of Device: ", 
3772                                 BACnetReinitializedStateOfDevice);
3773                         break;
3774                 case 1: /* password */
3775                         offset = fCharacterString (tvb, tree, offset, "Password: ");
3776                         break;
3777                 default:
3778                         return offset;
3779                         break;
3780                 }
3781         }
3782         return offset;
3783 }
3784
3785 static guint
3786 fVtOpenRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3787 {
3788         offset = fApplicationTypesEnumerated (tvb, tree, offset, 
3789                 "vtClass: ", BACnetVTClass);
3790         return fApplicationTypes (tvb,tree,offset,"local VT Session ID: ");
3791 }
3792
3793 static guint
3794 fVtOpenAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3795 {
3796         return fApplicationTypes (tvb,tree,offset,"remote VT Session ID: ");
3797 }
3798
3799 static guint
3800 fVtCloseRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3801 {
3802         guint lastoffset = 0;
3803
3804         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3805                 lastoffset = offset;
3806                 offset= fApplicationTypes (tvb,tree,offset,"remote VT Session ID: ");
3807         }
3808         return offset;
3809 }
3810
3811 static guint
3812 fVtDataRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3813 {
3814         offset= fApplicationTypes (tvb,tree,offset,"VT Session ID: ");
3815         offset = fApplicationTypes (tvb, tree, offset, "VT New Data: ");
3816         return fApplicationTypes (tvb,tree,offset,"VT Data Flag: ");;
3817 }
3818
3819 static guint
3820 fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3821 {
3822         guint lastoffset = 0;
3823
3824         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3825                 lastoffset = offset;
3826         
3827                 switch (fTagNo(tvb,offset)) {
3828                 case 0: /* BOOLEAN */
3829                         offset = fBooleanTag (tvb, tree, offset, "all New Data Accepted: ");
3830                         break;
3831                 case 1: /* Unsigned OPTIONAL */
3832                         offset = fUnsignedTag (tvb, tree, offset, "accepted Octet Count: ");
3833                         break;
3834                 default:
3835                         return offset;
3836                 }
3837         }
3838         return offset;
3839 }
3840
3841 static guint
3842 fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3843 {
3844         guint lastoffset = 0;
3845
3846         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3847                 lastoffset = offset;
3848         
3849                 switch (fTagNo(tvb,offset)) {
3850                 case 0: /* Unsigned32 */
3851                         offset = fUnsignedTag (tvb, tree, offset, "pseudo Random Number: ");
3852                         break;
3853                 case 1: /* expected Invoke ID Unsigned8 OPTIONAL */
3854                         proto_tree_add_item(tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
3855                         break;
3856                 case 2: /* Chararacter String OPTIONAL */
3857                         offset = fCharacterString (tvb, tree, offset, "operator Name: ");
3858                         break;
3859                 case 3: /* Chararacter String OPTIONAL */
3860                         offset = fCharacterString (tvb, tree, offset, "operator Password: ");
3861                         break;
3862                 case 4: /* Boolean OPTIONAL */
3863                         offset = fBooleanTag (tvb, tree, offset, "start Encyphered Session: ");
3864                         break;
3865                 default:
3866                         return offset;
3867                 }
3868         }
3869         return offset;
3870 }
3871
3872 static guint
3873 fAuthenticateAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3874 {
3875         return fApplicationTypes (tvb, tree, offset, "modified Random Number: ");
3876 }
3877
3878 static guint
3879 fRequestKeyRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
3880 {
3881         offset = fObjectIdentifier (tvb, tree, offset); /* Requesting Device Identifier */
3882         offset = fAddress (tvb, tree, offset);
3883         offset = fObjectIdentifier (tvb, tree, offset); /* Remote Device Identifier */
3884         return fAddress (tvb, tree, offset);
3885 }
3886
3887 static guint
3888 fRemoveListElementRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3889 {
3890         /* Same as AddListElement request after service choice */
3891         return fAddListElementRequest(tvb, tree, offset);
3892 }
3893
3894 static guint
3895 fReadPropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3896 {
3897         return fBACnetObjectPropertyReference(tvb, tree, offset);
3898 }
3899
3900 static guint
3901 fReadPropertyAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
3902 {
3903         guint lastoffset = 0;
3904         guint8 tag_no, tag_info;
3905         guint32 lvt;
3906         proto_tree *subtree = tree;
3907     proto_item *tt;
3908
3909         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3910                 lastoffset = offset;
3911                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
3912                 if (tag_is_closing(tag_info)) {
3913                         offset += fTagHeaderTree (tvb, subtree, offset,
3914                                 &tag_no, &tag_info, &lvt);
3915                         subtree = tree;
3916                         continue;
3917                 }
3918                 switch (tag_no) {
3919                 case 0: /* objectIdentifier */
3920                         offset = fObjectIdentifier (tvb, subtree, offset);
3921                         break;
3922                 case 1: /* propertyIdentifier */
3923                         offset = fPropertyIdentifier (tvb, subtree, offset);
3924                         break;
3925                 case 2: /* propertyArrayIndex */
3926                         offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
3927                         break;
3928                 case 3: /* propertyValue */
3929                         if (tag_is_opening(tag_info)) {
3930                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
3931                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
3932                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3933                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3934                                 break;
3935                         }
3936                         FAULT;
3937                         break;
3938                 default:
3939                         break;
3940                 }
3941         }
3942         return offset;
3943 }
3944
3945 static guint
3946 fWritePropertyRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
3947 {
3948         guint lastoffset = 0;
3949         guint8 tag_no, tag_info;
3950         guint32 lvt;
3951         proto_tree *subtree = tree;
3952     proto_item *tt;
3953
3954         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
3955                 lastoffset = offset;
3956                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
3957                 if (tag_is_closing(tag_info)) {
3958                         offset += fTagHeaderTree (tvb, subtree, offset,
3959                                 &tag_no, &tag_info, &lvt);
3960                         subtree = tree;
3961                         continue;
3962                 }
3963         
3964                 switch (tag_no) {
3965                 case 0: /* objectIdentifier */
3966                         offset = fObjectIdentifier (tvb, subtree, offset);
3967                         break;
3968                 case 1: /* propertyIdentifier */
3969                         offset = fPropertyIdentifier (tvb, subtree, offset);
3970                         break;
3971                 case 2: /* propertyArrayIndex */
3972                         offset = fSignedTag (tvb, subtree, offset, "property Array Index: ");
3973                         break;
3974                 case 3: /* propertyValue */
3975                         if (tag_is_opening(tag_info)) {
3976                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
3977                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
3978                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
3979                                 offset = fAbstractSyntaxNType (tvb, subtree, offset);
3980                                 break;
3981                         }
3982                         FAULT;
3983                         break;
3984                 case 4: /* Priority (only used for write) */
3985                         offset = fSignedTag (tvb, subtree, offset, "Priority: ");
3986                         break;
3987                 default:
3988                         return offset;
3989                 }
3990         }
3991         return offset;
3992 }
3993
3994 static guint
3995 fWriteAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
3996 {
3997         guint lastoffset = 0;
3998         guint8 tag_no, tag_info;
3999         guint32 lvt;
4000
4001         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4002                 lastoffset = offset;
4003                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4004                 if (tag_is_closing(tag_info)) {   
4005                         offset += fTagHeaderTree (tvb, subtree, offset,
4006                                 &tag_no, &tag_info, &lvt);
4007                         continue;
4008                 }
4009         
4010                 switch (tag_no) {
4011                 case 0: /* objectIdentifier */
4012                         offset = fObjectIdentifier (tvb, subtree, offset);
4013                         break;
4014                 case 1: /* listOfPropertyValues */
4015                         if (tag_is_opening(tag_info)) {
4016                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4017                                 offset = fBACnetPropertyValue (tvb, subtree, offset);
4018                                 break;
4019                         }
4020                         FAULT;
4021                         break;
4022                 default:
4023                         return offset;
4024                 }
4025         }
4026         return offset;
4027 }
4028
4029 static guint
4030 fWritePropertyMultipleRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4031 {
4032         if (offset >= tvb_reported_length(tvb))
4033                 return offset;
4034
4035         return fWriteAccessSpecification (tvb, tree, offset);
4036 }
4037
4038 static guint
4039 fPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 tagoffset, guint8 list)
4040 {
4041         guint lastoffset = 0;
4042         guint8 tag_no, tag_info;
4043         guint32 lvt;
4044
4045         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4046                 lastoffset = offset;
4047                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4048                 if (tag_is_closing(tag_info)) { /* closing Tag, but not for me */
4049                         return offset;
4050                 }
4051                 switch (tag_no-tagoffset) {
4052                 case 0: /* PropertyIdentifier */
4053                         offset = fPropertyIdentifier (tvb, tree, offset);
4054                         break;
4055                 case 1: /* propertyArrayIndex */
4056                         offset = fUnsignedTag (tvb, tree, offset, "property Array Index: ");
4057                         if (list != 0) break; /* Continue decoding if this may be a list */
4058                 default:
4059                         lastoffset = offset; /* Set loop end condition */
4060                         break;
4061                 }
4062         }
4063         return offset;
4064 }
4065
4066 static guint
4067 fBACnetPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset, guint8 list)
4068 {
4069         return fPropertyReference(tvb, tree, offset, 0, list);
4070 }
4071
4072 static guint
4073 fBACnetObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
4074 {
4075         guint lastoffset = 0;
4076
4077         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4078                 lastoffset = offset;
4079                 
4080                 switch (fTagNo(tvb,offset)) {
4081                 case 0: /* ObjectIdentifier */
4082                         offset = fObjectIdentifier (tvb, tree, offset);
4083                         break;
4084                 case 1: /* PropertyIdentifier and propertyArrayIndex */
4085                         offset = fPropertyReference (tvb, tree, offset, 1, 0);
4086                 default:
4087                         lastoffset = offset; /* Set loop end condition */
4088                         break;
4089                 }
4090         }
4091         return offset;
4092 }
4093
4094 #if 0
4095 static guint
4096 fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
4097 {
4098         guint lastoffset = 0;
4099         guint8 tag_no, tag_info;
4100         guint32 lvt;
4101         proto_tree* subtree = tree;
4102         proto_item* tt;
4103
4104         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4105                 lastoffset = offset;
4106                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4107                 if (tag_is_closing(tag_info)) {
4108                         offset += fTagHeaderTree (tvb, subtree, offset,
4109                                 &tag_no, &tag_info, &lvt);
4110                         continue;
4111                 }
4112                 switch (tag_no) {
4113                 case 0: /* ObjectIdentifier */
4114                         offset = fObjectIdentifier (tvb, subtree, offset);
4115                         break;
4116                 case 1: /* PropertyIdentifier */
4117                         offset = fPropertyIdentifier (tvb, subtree, offset);
4118                         break;
4119                 case 2: /* propertyArrayIndex */
4120                         offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
4121                         break;
4122                 case 3:  /* Value */
4123                         if (tag_is_opening(tag_info)) {
4124                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyValue");
4125                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4126                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4127                                 offset = fAbstractSyntaxNType   (tvb, subtree, offset);
4128                                 break;
4129                         }
4130                         FAULT;
4131                         break;
4132                 case 4:  /* Priority */
4133                         offset = fSignedTag (tvb, subtree, offset, "Priority: ");
4134                         break;
4135                 default:
4136                         break;
4137                 }
4138         }
4139         return offset;
4140 }
4141 #endif
4142
4143 #if 0
4144 static guint
4145 fDeviceObjectPropertyReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
4146 {
4147         guint lastoffset = 0;
4148
4149         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4150                 lastoffset = offset;
4151                 
4152                 switch (fTagNo(tvb,offset)) {
4153                 case 0: /* ObjectIdentifier */
4154                         offset = fBACnetObjectPropertyReference (tvb, tree, offset);
4155                         break;
4156                 case 3: /* deviceIdentifier */
4157                         offset = fObjectIdentifier (tvb, tree, offset);
4158                         break;
4159                 default:
4160                         return offset;
4161                 }
4162         }
4163         return offset;
4164 }
4165 #endif
4166
4167 static guint
4168 fPriorityArray (tvbuff_t *tvb, proto_tree *tree, guint offset)
4169 {
4170         char i, ar[256];
4171
4172         if (offset >= tvb_reported_length(tvb))
4173                 return offset;
4174         
4175         for (i = 1; i <= 16; i++) {
4176                 g_snprintf (ar, sizeof(ar), "%s[%d]: ",
4177                         val_to_split_str(87 , 512,
4178                                 BACnetPropertyIdentifier,
4179                                 ASHRAE_Reserved_Fmt,
4180                                 Vendor_Proprietary_Fmt),
4181                         i);
4182                 /* DMR Replace with fAbstractNSyntax */
4183                 offset = fApplicationTypes(tvb, tree, offset, ar);
4184         }
4185         return offset;
4186 }
4187
4188 #if 0
4189 static guint
4190 fDeviceObjectReference (tvbuff_t *tvb, proto_tree *tree, guint offset)
4191 {
4192         guint lastoffset = 0;
4193
4194         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4195                 lastoffset = offset;
4196                 
4197                 switch (fTagNo(tvb,offset)) {
4198                 case 0: /* deviceIdentifier */
4199                         offset = fObjectIdentifier (tvb, tree, offset);
4200                         break;
4201                 case 1: /* ObjectIdentifier */
4202                         offset = fObjectIdentifier (tvb, tree, offset);
4203                         break;
4204                 default:
4205                         return offset;
4206                 }
4207         }
4208         return offset;
4209 }
4210 #endif
4211
4212 static guint
4213 fSpecialEvent (tvbuff_t *tvb, proto_tree *subtree, guint offset)
4214 {
4215         guint8 tag_no, tag_info;
4216         guint32 lvt;
4217         guint lastoffset = 0;
4218
4219         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4220                 lastoffset = offset;
4221                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4222                 if (tag_is_closing(tag_info)) {   
4223                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4224                         continue;
4225                 }
4226         
4227                 switch (fTagNo(tvb,offset)) {
4228                 case 0: /* calendaryEntry */
4229                         offset = fCalendaryEntry (tvb, subtree, offset);
4230                         break;
4231                 case 1: /* calendarReference */
4232                         offset = fObjectIdentifier (tvb, subtree, offset);
4233                         break;
4234                 case 2: /* calendarReference */
4235                         if (tag_is_opening(tag_info)) {
4236                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4237                                 offset = fTimeValue (tvb, subtree, offset);
4238                                 break;
4239                         }
4240                         FAULT;
4241                         break;
4242                 case 3: /* eventPriority */
4243                         offset = fUnsignedTag (tvb, subtree, offset, "event priority: ");
4244                         break;
4245                 default:
4246                         return offset;
4247                 }
4248         }
4249         return offset;
4250 }
4251
4252 static guint
4253 fSelectionCriteria (tvbuff_t *tvb, proto_tree *tree, guint offset)
4254 {
4255         guint lastoffset = 0;
4256
4257         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4258                 lastoffset = offset;
4259                 
4260                 switch (fTagNo(tvb,offset)) {
4261                 case 0: /* propertyIdentifier */
4262                         offset = fPropertyIdentifier (tvb, tree, offset);
4263                         break;
4264                 case 1: /* propertyArrayIndex */
4265                         offset = fUnsignedTag (tvb, tree, offset, "property Array Index: ");
4266                         break;
4267                 case 2: /* relationSpecifier */
4268                         offset = fEnumeratedTag (tvb, tree, offset, 
4269                                 "relation Specifier: ", BACnetRelationSpecifier);
4270                         break;
4271                 case 3: /* comparisonValue */
4272                         offset = fAbstractSyntaxNType   (tvb, tree, offset);
4273                         break;
4274                 default:
4275                         return offset;
4276                 }
4277         }
4278         return offset;
4279 }
4280
4281 static guint
4282 fObjectSelectionCriteria (tvbuff_t *tvb, proto_tree *subtree, guint offset)
4283 {
4284         guint lastoffset = 0;
4285         guint8 tag_no, tag_info;
4286         guint32 lvt;
4287
4288         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4289                 lastoffset = offset;
4290                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4291                 if (tag_is_closing(tag_info)) {  
4292                         offset += fTagHeaderTree (tvb, subtree, offset,
4293                                 &tag_no, &tag_info, &lvt);
4294                         continue;
4295                 }
4296         
4297                 switch (tag_no) {
4298                 case 0: /* selectionLogic */
4299                         offset = fEnumeratedTag (tvb, subtree, offset, 
4300                                 "selection Logic: ", BACnetSelectionLogic);
4301                         break;
4302                 case 1: /* listOfSelectionCriteria */
4303                         if (tag_is_opening(tag_info)) {
4304                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4305                                 offset = fSelectionCriteria (tvb, subtree, offset);
4306                                 break;
4307                         }
4308                         FAULT;
4309                         break;
4310                 default:
4311                         return offset;
4312                 }
4313         }
4314         return offset;
4315 }
4316
4317
4318 static guint
4319 fReadPropertyConditionalRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
4320 {
4321         guint lastoffset = 0;
4322         guint8 tag_no, tag_info;
4323         guint32 lvt;
4324
4325         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4326                 lastoffset = offset;
4327                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4328                 if (tag_is_closing(tag_info)) {   
4329                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4330                         continue;
4331                 }
4332         
4333                 switch (tag_no) {
4334                 case 0: /* objectSelectionCriteria */
4335                         offset = fObjectSelectionCriteria (tvb, subtree, offset);
4336                         break;
4337                 case 1: /* listOfPropertyReferences */
4338                         if (tag_is_opening(tag_info)) {
4339                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4340                                 offset = fBACnetPropertyReference (tvb, subtree, offset, 1);
4341                                 break;
4342                         }
4343                         FAULT;
4344                         break;
4345                 default:
4346                         return offset;
4347                 }
4348         }
4349         return offset;
4350 }
4351
4352 static guint
4353 fReadAccessSpecification (tvbuff_t *tvb, proto_tree *subtree, guint offset)
4354 {
4355         guint lastoffset = 0;
4356         guint8 tag_no, tag_info;
4357         guint32 lvt;
4358
4359         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4360                 lastoffset = offset;
4361                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4362                 if (tag_is_closing(tag_info)) {   
4363                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no,
4364                                 &tag_info, &lvt);
4365                         continue;
4366                 }
4367         
4368                 switch (tag_no) {
4369                 case 0: /* objectIdentifier */
4370                         offset = fObjectIdentifier (tvb, subtree, offset);
4371                         break;
4372                 case 1: /* listOfPropertyReferences */
4373                         if (tag_is_opening(tag_info)) {
4374                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4375                                 offset = fBACnetPropertyReference (tvb, subtree, offset, 1);
4376                                 break;
4377                         }
4378                         FAULT;
4379                         break;
4380                 default:
4381                         return offset;
4382                 }
4383         }
4384         return offset;
4385 }
4386
4387 static guint
4388 fReadAccessResult (tvbuff_t *tvb, proto_tree *tree, guint offset)
4389 {
4390         guint lastoffset = 0;
4391         guint8 tag_no;
4392         guint8 tag_info;
4393         guint32 lvt;
4394         proto_tree *subtree = tree;
4395         proto_item *tt;
4396
4397         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4398                 lastoffset = offset;
4399                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4400                 if (tag_is_closing(tag_info)) {   
4401                         offset += fTagHeaderTree (tvb, subtree, offset,
4402                                 &tag_no, &tag_info, &lvt);
4403                         if (tag_no == 4 || tag_no == 5) subtree = tree; /* Value and error have extra subtree */
4404                         continue;
4405                 }
4406         
4407                 switch (tag_no) {
4408                 case 0: /* objectSpecifier */
4409                         offset = fObjectIdentifier (tvb, subtree, offset);
4410                         break;
4411                 case 1: /* list of Results */
4412                         if (tag_is_opening(tag_info)) {
4413                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfResults");
4414                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4415                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4416                                 break;
4417                         }
4418                         FAULT;
4419                         break;
4420                 case 2: /* propertyIdentifier */
4421                         offset = fPropertyValue(tvb, subtree, offset, 2);
4422                         break;
4423                 case 5: /* propertyAccessError */
4424                         if (tag_is_opening(tag_info)) {
4425                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyAccessError");
4426                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4427                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4428                                 /* Error Code follows */
4429                                 offset = fError(tvb, subtree, offset);
4430                                 break;
4431                         }
4432                         FAULT;
4433                         break;
4434                 default:
4435                         return offset;
4436                 }
4437         }
4438         return offset;
4439 }
4440
4441
4442 static guint
4443 fReadPropertyConditionalAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4444 {
4445         /* listOfReadAccessResults */
4446         return fReadAccessResult (tvb, tree, offset);
4447 }
4448
4449
4450 static guint
4451 fObjectSpecifier (tvbuff_t *tvb, proto_tree *tree, guint offset)
4452 {
4453         guint lastoffset = 0;
4454
4455         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4456                 lastoffset = offset;
4457                 switch (fTagNo(tvb, offset)) {
4458                 case 0: /* objectType */
4459                         proto_tree_add_item(tree, hf_bacapp_tag_initiatingObjectType, tvb, offset++, 1, TRUE);
4460                         break;
4461                 case 1: /* objectIdentifier */
4462                         offset = fObjectIdentifier (tvb, tree, offset);
4463                         break;
4464                 default:
4465                         return offset;
4466                 }
4467         }
4468         return offset;
4469 }
4470
4471 static guint
4472 fCreateObjectRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
4473 {
4474         guint lastoffset = 0;
4475         guint8 tag_no, tag_info;
4476         guint32 lvt;
4477
4478         while ((tvb_length_remaining(tvb, offset) > 0) && (offset > lastoffset)) {  /* exit loop if nothing happens inside */
4479                 lastoffset = offset;
4480                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4481                 if (tag_is_closing(tag_info)) {   
4482                         offset += fTagHeaderTree (tvb, subtree, offset,
4483                                 &tag_no, &tag_info, &lvt);
4484                         continue;
4485                 }
4486         
4487                 switch (tag_no) {
4488                 case 0: /* objectSpecifier */
4489                         offset = fObjectSpecifier (tvb, subtree, offset);
4490                         break;
4491                 case 1: /* propertyValue */
4492                         if (tag_is_opening(tag_info)) {
4493                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4494                                 offset = fBACnetPropertyValue (tvb, subtree, offset);
4495                                 break;
4496                         }
4497                         FAULT;
4498                         break;
4499                 default:
4500                         return offset;
4501                 }
4502         }
4503         return offset;
4504 }
4505
4506 static guint
4507 fCreateObjectAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4508 {
4509         return fObjectIdentifier (tvb, tree, offset);
4510 }
4511
4512 static guint
4513 fReadRangeRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
4514 {
4515         guint lastoffset = 0;
4516         guint8 tag_no, tag_info;
4517         guint32 lvt;
4518         proto_tree *subtree = tree;
4519         proto_item *tt;
4520
4521         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4522                 lastoffset = offset;
4523                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4524                 if (tag_is_closing(tag_info)) {  
4525                         offset += fTagHeaderTree (tvb, subtree, offset,
4526                                 &tag_no, &tag_info, &lvt);
4527                         subtree = tree;
4528                         continue;
4529                 }
4530         
4531                 switch (tag_no) {
4532                 case 0: /* objectSpecifier */
4533                         offset = fObjectIdentifier (tvb, subtree, offset);
4534                         break;
4535                 case 1: /* propertyIdentifier */
4536                         offset = fPropertyIdentifier (tvb, subtree, offset);
4537                         break;
4538                 case 2: /* propertyArrayIndex Optional */
4539                         offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
4540                         break;
4541                 case 3: /* range byPosition */
4542                         if (tag_is_opening(tag_info)) {
4543                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "range byPosition");
4544                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4545                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4546                                 offset = fApplicationTypes (tvb, subtree, offset, "reference Index: ");
4547                                 offset = fApplicationTypes (tvb, subtree, offset, "reference Count: ");
4548                                 break;
4549                         }
4550                         FAULT;
4551                         break;
4552                 case 4: /* range byTime */
4553                         if (tag_is_opening(tag_info)) {
4554                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "range byTime");
4555                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4556                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4557                                 offset = fApplicationTypes (tvb, subtree, offset, "reference Time: ");
4558                                 offset = fApplicationTypes (tvb, subtree, offset, "reference Count: ");
4559                                 break;
4560                         }
4561                         FAULT;
4562                         break;
4563                 case 5: /* range timeRange */
4564                         if (tag_is_opening(tag_info)) {
4565                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "range timeRange");
4566                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4567                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4568                                 offset = fApplicationTypes (tvb, subtree, offset, "beginning Time: ");
4569                                 offset = fApplicationTypes (tvb, subtree, offset, "ending Time: ");
4570                                 break;
4571                         }
4572                         FAULT;
4573                         break;
4574                 default:
4575                         return offset;
4576                 }
4577         }
4578         return offset;
4579 }
4580
4581 static guint
4582 fReadRangeAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4583 {
4584         guint lastoffset = 0;
4585         guint8 tag_no, tag_info;
4586         guint32 lvt;
4587         proto_tree *subtree = tree;
4588         proto_item *tt;
4589
4590         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4591                 lastoffset = offset;
4592                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4593                 if (tag_is_closing(tag_info)) {
4594                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4595                         subtree = tree;
4596                         continue;
4597                 }
4598         
4599                 switch (tag_no) {
4600                 case 0: /* objectSpecifier */
4601                         offset = fObjectIdentifier (tvb, subtree, offset);
4602                         break;
4603                 case 1: /* propertyIdentifier */
4604                         offset = fPropertyIdentifier (tvb, subtree, offset);
4605                         break;
4606                 case 2: /* propertyArrayIndex Optional */
4607                         offset = fUnsignedTag (tvb, subtree, offset, "Property Array Index: ");
4608                         break;
4609                 case 3: /* resultFlags */
4610                         offset = fEnumeratedTag (tvb, tree, offset, 
4611                                 "result Flags: ", BACnetResultFlags);
4612                         break;
4613                 case 4: /* itemCount */
4614                         offset = fUnsignedTag (tvb, subtree, offset, "item Count: ");
4615                         break;
4616                 case 5: /* itemData */
4617                         if (tag_is_opening(tag_info)) {
4618                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "itemData");
4619                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4620                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4621                                 offset = fAbstractSyntaxNType   (tvb, subtree, offset);
4622                                 break;
4623                         }
4624                         FAULT;
4625                         break;
4626                 case 6: /* firstSequenceNumber */
4627                         offset = fUnsignedTag (tvb, subtree, offset, "first Sequence Number: ");
4628                         break;
4629                 default:
4630                         return offset;
4631                 }
4632         }
4633         return offset;
4634 }
4635
4636 static guint fAccessMethod(tvbuff_t *tvb, proto_tree *tree, guint offset)
4637 {
4638         guint32 lvt;
4639         guint8 tag_no, tag_info;
4640         proto_item* tt;
4641         proto_tree* subtree = NULL;
4642
4643         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4644
4645         switch (tag_no) {
4646         case 0: /* streamAccess */
4647                 if (tag_is_opening(tag_info)) {  
4648                         tt = proto_tree_add_text(tree, tvb, offset, 1, "stream Access");
4649                         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4650                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4651                         offset = fApplicationTypes (tvb, subtree, offset, "File Start Position: ");
4652                         offset = fApplicationTypes (tvb, subtree, offset, "file Data: ");
4653                 }
4654                 if (bacapp_flags & 0x04) { /* More Flag is set */
4655                         break;
4656                 }
4657                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4658                 if (tag_is_closing(tag_info)) {
4659                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4660                 }
4661                 break;
4662         case 1: /* recordAccess */
4663                 if (tag_is_opening(tag_info)) {
4664                         tt = proto_tree_add_text(tree, tvb, offset, 1, "record Access");
4665                         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4666                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4667                         offset = fApplicationTypes (tvb, subtree, offset, "File Start Record: ");
4668                         offset = fApplicationTypes (tvb, subtree, offset, "Record Count: ");
4669                         offset = fApplicationTypes (tvb, subtree, offset, "Data: ");
4670                 }
4671                 if (bacapp_flags & 0x04) { /* More Flag is set */
4672                         break;
4673                 }
4674                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4675                 if (tag_is_closing(tag_info)) {
4676                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4677                 }
4678                 break;
4679         default:
4680                 break;
4681         }
4682         
4683         return offset;
4684 }
4685
4686 static guint
4687 fAtomicReadFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4688 {
4689         guint lastoffset = 0;
4690         guint8 tag_no, tag_info;
4691         guint32 lvt;
4692         proto_tree *subtree = tree;
4693         proto_item *tt;
4694
4695         offset = fObjectIdentifier (tvb, tree, offset);
4696
4697         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4698                 lastoffset = offset;
4699                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4700                 if (tag_is_closing(tag_info)) { 
4701                         offset += fTagHeaderTree (tvb, subtree, offset,
4702                                 &tag_no, &tag_info, &lvt);
4703                         subtree = tree;
4704                         continue;
4705                 }
4706
4707                 switch (tag_no) {
4708                 case 0: /* streamAccess */
4709                         if (tag_is_opening(tag_info)) {
4710                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "stream Access");
4711                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4712                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4713                                 offset = fSignedTag (tvb, subtree, offset, "File Start Position: ");
4714                                 offset = fUnsignedTag (tvb, subtree, offset, "requested Octet Count: ");
4715                                 break;
4716                         }
4717                         FAULT;
4718                         break;
4719                 case 1: /* recordAccess */
4720                         if (tag_is_opening(tag_info)) {
4721                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "record Access");
4722                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
4723                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4724                                 offset = fSignedTag (tvb, subtree, offset, "File Start Record: ");
4725                                 offset = fUnsignedTag (tvb, subtree, offset, "requested Record Count: ");
4726                                 break;
4727                         }
4728                         FAULT;
4729                         break;
4730                 default:
4731                         return offset;
4732                 }
4733         }
4734         return offset;
4735 }
4736
4737 static guint
4738 fAtomicWriteFileRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
4739 {
4740
4741         offset = fObjectIdentifier (tvb, tree, offset); /* file Identifier */
4742     offset = fAccessMethod(tvb, tree, offset);
4743
4744         return offset;
4745 }
4746
4747 static guint
4748 fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4749 {
4750         switch (fTagNo(tvb, offset)) {
4751         case 0: /* streamAccess */
4752                 offset = fSignedTag (tvb, tree, offset, "File Start Position: ");
4753                 break;
4754         case 1: /* recordAccess */
4755                 offset = fSignedTag (tvb, tree, offset, "File Start Record: ");
4756                 break;
4757         default:
4758                 return offset;
4759         }
4760         return offset;
4761 }
4762
4763 static guint
4764 fAtomicReadFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4765 {
4766         guint8 tag_no, tag_info;
4767         guint32 lvt;
4768         proto_tree *subtree = tree;
4769
4770         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4771         offset = fApplicationTypes (tvb, subtree, offset, "End Of File: ");
4772     offset = fAccessMethod(tvb, tree, offset);
4773
4774     return offset;
4775 }
4776
4777 static guint
4778 fReadPropertyMultipleRequest(tvbuff_t *tvb, proto_tree *subtree, guint offset)
4779 {
4780         return fReadAccessSpecification (tvb,subtree,offset);
4781 }
4782
4783 static guint
4784 fReadPropertyMultipleAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
4785 {
4786         return fReadAccessResult (tvb,tree,offset);
4787 }
4788
4789 static guint
4790 fConfirmedServiceRequest (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
4791 {
4792         if (tvb_length_remaining(tvb,offset) <= 0)
4793                 return offset;
4794
4795         switch (service_choice) {
4796         case 0: /* acknowledgeAlarm */
4797                 offset = fAcknowlegdeAlarmRequest (tvb, tree, offset);
4798                 break;
4799         case 1: /* confirmedCOVNotification */
4800                 offset = fConfirmedCOVNotificationRequest (tvb, tree, offset);
4801                 break;
4802         case 2: /* confirmedEventNotification */
4803                 offset = fConfirmedEventNotificationRequest (tvb, tree, offset);
4804                 break;
4805         case 3: /* confirmedGetAlarmSummary conveys no parameters */
4806                 break;
4807         case 4: /* getEnrollmentSummaryRequest */
4808                 offset = fGetEnrollmentSummaryRequest (tvb, tree, offset);
4809                 break;
4810         case 5: /* subscribeCOVRequest */
4811                 offset = fSubscribeCOVRequest(tvb, tree, offset);
4812                 break;
4813         case 6: /* atomicReadFile-Request */
4814                 offset = fAtomicReadFileRequest(tvb, tree, offset);
4815                 break;
4816         case 7: /* atomicWriteFile-Request */
4817                 offset = fAtomicWriteFileRequest(tvb, tree, offset);
4818                 break;
4819         case 8: /* AddListElement-Request */
4820                 offset = fAddListElementRequest(tvb, tree, offset);
4821                 break;
4822         case 9: /* removeListElement-Request */
4823                 offset = fRemoveListElementRequest(tvb, tree, offset);
4824                 break;
4825         case 10: /* createObjectRequest */
4826                 offset = fCreateObjectRequest(tvb, tree, offset);
4827                 break;
4828         case 11: /* deleteObject */
4829                 offset = fDeleteObjectRequest(tvb, tree, offset);
4830                 break;
4831         case 12:
4832                 offset = fReadPropertyRequest(tvb, tree, offset);
4833                 break;
4834         case 13:
4835                 offset = fReadPropertyConditionalRequest(tvb, tree, offset);
4836                 break;
4837         case 14:
4838                 offset = fReadPropertyMultipleRequest(tvb, tree, offset);
4839                 break;
4840         case 15:
4841                 offset = fWritePropertyRequest(tvb, tree, offset);
4842                 break;
4843         case 16:
4844                 offset = fWritePropertyMultipleRequest(tvb, tree, offset);
4845                 break;
4846         case 17:
4847                 offset = fDeviceCommunicationControlRequest(tvb, tree, offset);
4848                 break;
4849         case 18:
4850                 offset = fConfirmedPrivateTransferRequest(tvb, tree, offset);
4851                 break;
4852         case 19:
4853                 offset = fConfirmedTextMessageRequest(tvb, tree, offset);
4854                 break;
4855         case 20:
4856                 offset = fReinitializeDeviceRequest(tvb, tree, offset);
4857                 break;
4858         case 21:
4859                 offset = fVtOpenRequest(tvb, tree, offset);
4860                 break;
4861         case 22:
4862                 offset = fVtCloseRequest (tvb, tree, offset);
4863                 break;
4864         case 23:
4865                 offset = fVtDataRequest (tvb, tree, offset);
4866                 break;
4867         case 24:
4868                 offset = fAuthenticateRequest (tvb, tree, offset);
4869                 break;
4870         case 25:
4871                 offset = fRequestKeyRequest (tvb, tree, offset);
4872                 break;
4873         case 26:
4874                 offset = fReadRangeRequest (tvb, tree, offset);
4875                 break;
4876         case 27:
4877                 offset = fLifeSafetyOperationRequest(tvb, tree, offset, NULL);
4878                 break;
4879         case 28:
4880                 offset = fSubscribeCOVPropertyRequest(tvb, tree, offset);
4881                 break;
4882         case 29:
4883                 offset = fGetEventInformationRequest (tvb, tree, offset);
4884                 break;
4885         default:
4886                 return offset;
4887                 break;
4888         }
4889         return offset;
4890 }
4891
4892 static guint
4893 fConfirmedServiceAck (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
4894 {
4895         if (tvb_length_remaining(tvb,offset) <= 0)
4896                 return offset;
4897
4898         switch (service_choice) {
4899         case 3: /* confirmedEventNotificationAck */
4900                 offset = fGetAlarmSummaryAck (tvb, tree, offset);
4901                 break;
4902         case 4: /* getEnrollmentSummaryAck */
4903                 offset = fGetEnrollmentSummaryAck (tvb, tree, offset);
4904                 break;
4905         case 6: /* atomicReadFile */
4906                 offset = fAtomicReadFileAck (tvb, tree, offset);
4907                 break;
4908         case 7: /* atomicReadFileAck */
4909                 offset = fAtomicWriteFileAck (tvb, tree, offset);
4910                 break;
4911         case 10: /* createObject */
4912                 offset = fCreateObjectAck (tvb, tree, offset);
4913                 break;
4914         case 12:
4915                 offset = fReadPropertyAck (tvb, tree, offset);
4916                 break;
4917         case 13:
4918                 offset = fReadPropertyConditionalAck (tvb, tree, offset);
4919                 break;
4920         case 14:
4921                 offset = fReadPropertyMultipleAck (tvb, tree, offset);
4922                 break;
4923         case 18:
4924                 offset = fConfirmedPrivateTransferAck(tvb, tree, offset);
4925                 break;
4926         case 21:
4927                 offset = fVtOpenAck (tvb, tree, offset);
4928                 break;
4929         case 23:
4930                 offset = fVtDataAck (tvb, tree, offset);
4931                 break;
4932         case 24:
4933                 offset = fAuthenticateAck (tvb, tree, offset);
4934                 break;
4935         case 26:
4936                 offset = fReadRangeAck (tvb, tree, offset);
4937                 break;
4938         case 29:
4939                 offset = fGetEventInformationACK (tvb, tree, offset);
4940                 break;
4941         default:
4942                 return offset;
4943         }
4944         return offset;
4945 }
4946
4947 static guint
4948 fIAmRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
4949 {
4950         /* BACnetObjectIdentifier */
4951         offset = fApplicationTypes (tvb, tree, offset, "BACnet Object Identifier: ");
4952
4953         /* MaxAPDULengthAccepted */
4954         offset = fApplicationTypes (tvb, tree, offset, "Maximum ADPU Length Accepted: ");
4955
4956         /* segmentationSupported */
4957         offset = fApplicationTypesEnumerated (tvb, tree, offset, 
4958                 "Segmentation Supported: ", BACnetSegmentation);
4959
4960         /* vendor ID */
4961         return fUnsignedTag (tvb, tree, offset, "Vendor ID: ");
4962 }
4963
4964 static guint
4965 fIHaveRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
4966 {
4967         /* BACnetDeviceIdentifier */
4968         offset = fApplicationTypes (tvb, tree, offset, "Device Identifier: ");
4969
4970         /* BACnetObjectIdentifier */
4971         offset = fApplicationTypes (tvb, tree, offset, "Object Identifier: ");
4972
4973         /* ObjectName */
4974         return fApplicationTypes (tvb, tree, offset, "Object Name: ");
4975
4976 }
4977
4978 static guint
4979 fWhoIsRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
4980 {
4981         guint lastoffset = 0;
4982
4983         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
4984                 lastoffset = offset;
4985                 switch (fTagNo(tvb, offset)) {
4986                 case 0: /* DeviceInstanceRangeLowLimit Optional */
4987                         offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range Low Limit: ");
4988                         break;
4989                 case 1: /* DeviceInstanceRangeHighLimit Optional but required if DeviceInstanceRangeLowLimit is there */
4990                         offset = fUnsignedTag (tvb, tree, offset, "Device Instance Range High Limit: ");
4991                         break;
4992                 default:
4993                         return offset;
4994                         break;
4995                 }
4996         }
4997         return offset;
4998 }
4999
5000 static guint
5001 fUnconfirmedServiceRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset, gint service_choice)
5002 {
5003         if (tvb_length_remaining(tvb,offset) <= 0)
5004                 return offset;
5005         
5006         switch (service_choice) {
5007         case 0: /* I-Am-Request */
5008                 offset = fIAmRequest  (tvb, tree, offset);
5009                 break;
5010         case 1: /* i-Have Request */
5011                 offset = fIHaveRequest  (tvb, tree, offset);
5012         break;
5013         case 2: /* unconfirmedCOVNotification */
5014                 offset = fUnconfirmedCOVNotificationRequest (tvb, tree, offset);
5015                 break;
5016         case 3: /* unconfirmedEventNotification */
5017                 offset = fUnconfirmedEventNotificationRequest (tvb, tree, offset);
5018                 break;
5019         case 4: /* unconfirmedPrivateTransfer */
5020                 offset = fUnconfirmedPrivateTransferRequest(tvb, tree, offset);
5021                 break;
5022         case 5: /* unconfirmedTextMessage */
5023                 offset = fUnconfirmedTextMessageRequest(tvb, tree, offset);
5024                 break;
5025         case 6: /* timeSynchronization */
5026                 offset = fTimeSynchronizationRequest  (tvb, tree, offset);
5027                 break;
5028         case 7: /* who-Has */
5029                 offset = fWhoHas (tvb, tree, offset);
5030                 break;
5031         case 8: /* who-Is */
5032                 offset = fWhoIsRequest  (tvb, tree, offset);
5033                 break;
5034         case 9: /* utcTimeSynchronization */
5035                 offset = fUTCTimeSynchronizationRequest  (tvb, tree, offset);
5036                 break;
5037         default:
5038                 break;
5039         }
5040         return offset;
5041 }
5042
5043 static guint
5044 fStartConfirmed(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset, guint8 ack,
5045                                 gint *svc, proto_item **tt)
5046 {
5047         proto_item *tc;
5048         proto_tree *bacapp_tree_control;
5049         gint tmp, bacapp_type;
5050         guint extra = 2;
5051
5052         bacapp_seq = 0;
5053         tmp = (gint) tvb_get_guint8(tvb, offset);
5054         bacapp_type = (tmp >> 4) & 0x0f;
5055         bacapp_flags = tmp & 0x0f;
5056
5057         if (ack == 0) {
5058                 extra = 3;
5059         }
5060         *svc = (gint) tvb_get_guint8(tvb, offset+extra);
5061         if (bacapp_flags & 0x08)
5062                 *svc = (gint) tvb_get_guint8(tvb, offset+extra+2);
5063
5064     proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
5065         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_pduflags, tvb, offset, 1, TRUE);
5066         bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp_control);
5067
5068     proto_tree_add_item(bacapp_tree_control, hf_bacapp_SEG, tvb, offset, 1, TRUE);
5069     proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, offset, 1, TRUE);
5070         if (ack == 0) /* The following are for ConfirmedRequest, not Complex ack */
5071         {
5072             proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, offset++, 1, TRUE);
5073                 proto_tree_add_item(bacapp_tree, hf_bacapp_response_segments, tvb,
5074                                                         offset, 1, TRUE);
5075                 proto_tree_add_item(bacapp_tree, hf_bacapp_max_adpu_size, tvb,
5076                                                         offset, 1, TRUE);
5077         }
5078     offset++;
5079     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, offset++, 1, TRUE);
5080     if (bacapp_flags & 0x08) {
5081         bacapp_seq = tvb_get_guint8(tvb, offset);
5082         proto_tree_add_item(bacapp_tree_control, hf_bacapp_sequence_number, tvb,
5083             offset++, 1, TRUE);
5084         proto_tree_add_item(bacapp_tree_control, hf_bacapp_window_size, tvb,
5085             offset++, 1, TRUE);
5086     }
5087     *tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
5088         offset++, 1, TRUE);
5089         return offset;
5090 }
5091
5092 static guint
5093 fConfirmedRequestPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5094 {       /* BACnet-Confirmed-Request */
5095         /* ASHRAE 135-2001 20.1.2 */
5096         gint svc;
5097         proto_item *tt = 0;
5098
5099         offset = fStartConfirmed(tvb, bacapp_tree, offset, 0, &svc, &tt);
5100         if (bacapp_seq > 0) /* Can't handle continuation segments, so just treat as data */
5101         {
5102                 proto_tree_add_text(bacapp_tree, tvb, offset, 0, "(continuation)");
5103                 return offset;
5104         }
5105         else
5106         {
5107                 /* Service Request follows... Variable Encoding 20.2ff */
5108                 return fConfirmedServiceRequest (tvb, bacapp_tree, offset, svc);
5109         }
5110 }
5111
5112 static guint
5113 fUnconfirmedRequestPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5114 {       /* BACnet-Unconfirmed-Request-PDU */
5115         /* ASHRAE 135-2001 20.1.3 */
5116
5117         gint tmp;
5118
5119     proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
5120
5121     tmp = tvb_get_guint8(tvb, offset);
5122     proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb,
5123             offset++, 1, TRUE);
5124     /* Service Request follows... Variable Encoding 20.2ff */
5125     return fUnconfirmedServiceRequest  (tvb, bacapp_tree, offset, tmp);
5126 }
5127
5128 static guint
5129 fSimpleAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5130 {       /* BACnet-Simple-Ack-PDU */
5131         /* ASHRAE 135-2001 20.1.4 */
5132
5133         proto_item *tc;
5134
5135         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
5136
5137     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5138         offset++, 1, TRUE);
5139     proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
5140         offset++, 1, TRUE);
5141         return offset;
5142 }
5143
5144 static guint
5145 fComplexAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5146 {       /* BACnet-Complex-Ack-PDU */
5147         /* ASHRAE 135-2001 20.1.5 */
5148         gint svc;
5149         proto_item *tt = 0;
5150
5151         offset = fStartConfirmed(tvb, bacapp_tree, offset, 1, &svc, &tt);
5152
5153         if (bacapp_seq > 0) /* Can't handle continuation segments, so just treat as data */
5154         {
5155                 proto_tree_add_text(bacapp_tree, tvb, offset, 0, "(continuation)");
5156                 return offset;
5157         }
5158         else
5159         {
5160             /* Service ACK follows... */
5161                 return fConfirmedServiceAck (tvb, bacapp_tree, offset, svc);
5162         }
5163 }
5164
5165
5166 static guint
5167 fSegmentAckPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5168 {       /* BACnet-SegmentAck-PDU */
5169         /* ASHRAE 135-2001 20.1.6 */
5170
5171         proto_item *tc;
5172         proto_tree *bacapp_tree_control;
5173
5174     tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
5175     bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
5176
5177     proto_tree_add_item(bacapp_tree, hf_bacapp_NAK, tvb, offset, 1, TRUE);
5178     proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, offset++, 1, TRUE);
5179     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5180         offset++, 1, TRUE);
5181     proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
5182             offset++, 1, TRUE);
5183     proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
5184             offset++, 1, TRUE);
5185         return offset;
5186 }
5187
5188 static guint fContextTaggedError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5189 {
5190     guint8 tag_info = 0;
5191     guint8 parsed_tag = 0;
5192     guint32 lvt = 0;
5193     offset += fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt);
5194     offset = fError(tvb, tree, offset);
5195     return offset + fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt);
5196 }
5197
5198 static guint
5199 fConfirmedPrivateTransferError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5200 {
5201         guint lastoffset = 0;
5202
5203         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
5204                 lastoffset = offset;
5205                 switch (fTagNo(tvb, offset)) {
5206                 case 0: /* errorType */
5207                         offset = fContextTaggedError(tvb,tree,offset);
5208                         break;
5209                 case 1: /* vendorID */
5210                         offset = fUnsignedTag (tvb,tree,offset,"vendor ID: ");
5211                         break;
5212                 case 2: /* serviceNumber */
5213                         offset = fUnsignedTag (tvb,tree,offset,"service Number: ");
5214                         break;
5215         case 3: /* errorParameters */
5216             offset = fAbstractSyntaxNType   (tvb, tree, offset);
5217             break;
5218                 default:
5219                         return offset;
5220                 }
5221         }
5222         return offset;
5223 }
5224
5225 static guint
5226 fCreateObjectError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5227 {
5228         guint lastoffset = 0;
5229
5230         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
5231                 lastoffset = offset;
5232                 switch (fTagNo(tvb, offset)) {
5233                 case 0: /* errorType */
5234                         offset = fContextTaggedError(tvb,tree,offset);
5235                         break;
5236                 case 1: /* firstFailedElementNumber */
5237                         offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
5238                         break;
5239                 default:
5240                         return offset;
5241                 }
5242         }
5243         return offset;
5244 }
5245
5246 static guint
5247 fChangeListError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5248 {
5249         guint lastoffset = 0;
5250
5251         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
5252                 lastoffset = offset;
5253                 switch (fTagNo(tvb, offset)) {
5254                 case 0: /* errorType */
5255                         offset = fContextTaggedError(tvb,tree,offset);
5256                         break;
5257                 case 1: /* firstFailedElementNumber */
5258                         offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
5259                         break;
5260                 default:
5261                         return offset;
5262                 }
5263         }
5264         return offset;
5265 }
5266
5267 #if 0
5268 static guint
5269 fVTSession(tvbuff_t *tvb, proto_tree *tree, guint offset)
5270 {
5271         if (tvb_length_remaining(tvb, offset) > 0) {    /* don't loop */
5272                 offset = fUnsignedTag (tvb,tree,offset, "local-VTSessionID: ");
5273                 offset = fUnsignedTag (tvb,tree,offset, "remote-VTSessionID: ");
5274                 offset = fAddress (tvb,tree,offset);
5275         }
5276         return offset;
5277 }
5278 #endif
5279
5280 static guint
5281 fVTCloseError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5282 {
5283         guint lastoffset = 0;
5284
5285         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
5286                 lastoffset = offset;
5287                 switch (fTagNo(tvb, offset)) {
5288                 case 0: /* errorType */
5289                         offset = fContextTaggedError(tvb,tree,offset);
5290                         break;
5291                 case 1: /* listOfVTSessionIdentifiers */
5292                         offset = fUnsignedTag (tvb,tree,offset,"VT SessionID: ");
5293                         break;
5294                 default:
5295                         return offset;
5296                 }
5297         }
5298         return offset;
5299 }
5300
5301 static guint
5302 fWritePropertyMultipleError(tvbuff_t *tvb, proto_tree *tree, guint offset)
5303 {
5304         guint lastoffset = 0;
5305
5306         while ((tvb_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
5307                 lastoffset = offset;
5308                 switch (fTagNo(tvb, offset)) {
5309                 case 0: /* errorType */
5310                         offset = fContextTaggedError(tvb,tree,offset);
5311                         break;
5312                 case 1: /* firstFailedWriteAttempt */
5313                         offset = fUnsignedTag (tvb,tree,offset,"first failed write attempt: ");
5314                         break;
5315                 default:
5316                         return offset;
5317                 }
5318         }
5319         return offset;
5320 }
5321
5322 static guint
5323 fError (tvbuff_t *tvb, proto_tree *tree, guint offset)
5324 {
5325     offset = fApplicationTypesEnumeratedSplit (tvb, tree, offset, 
5326         "error Class: ", BACnetErrorClass, 64);
5327     return fApplicationTypesEnumeratedSplit (tvb, tree, offset, 
5328         "error Code: ", BACnetErrorCode, 256);
5329 }
5330
5331 static guint
5332 fBACnetError (tvbuff_t *tvb, proto_tree *tree, guint offset, guint service)
5333 {
5334     switch (service) {
5335     case 8:  /* no break here !!!! */
5336     case 9:
5337         offset = fChangeListError (tvb, tree, offset);
5338         break;
5339     case 10:
5340         offset = fCreateObjectError (tvb,tree,offset);
5341         break;
5342     case 16:
5343         offset = fWritePropertyMultipleError (tvb,tree,offset);
5344         break;
5345     case 18:
5346         offset = fConfirmedPrivateTransferError (tvb,tree,offset);
5347     case 22:
5348         offset = fVTCloseError (tvb,tree,offset);
5349     default:
5350         return fError (tvb, tree, offset);
5351         break;
5352     }
5353     return offset;
5354 }
5355
5356 static guint
5357 fErrorPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5358 {       /* BACnet-Error-PDU */
5359         /* ASHRAE 135-2001 20.1.7 */
5360
5361         proto_item *tc, *tt;
5362         proto_tree *bacapp_tree_control;
5363     guint8 tmp;
5364
5365     tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
5366     bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
5367
5368     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5369         offset++, 1, TRUE);
5370     tmp = tvb_get_guint8(tvb, offset);
5371     tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
5372         offset++, 1, TRUE);
5373     /* Error Handling follows... */
5374     return fBACnetError (tvb, bacapp_tree, offset, tmp);
5375 }
5376
5377 static guint
5378 fRejectPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5379 {       /* BACnet-Reject-PDU */
5380         /* ASHRAE 135-2001 20.1.8 */
5381
5382         proto_item *tc;
5383         proto_tree *bacapp_tree_control;
5384
5385     tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, TRUE);
5386     bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
5387
5388     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5389         offset++, 1, TRUE);
5390     proto_tree_add_item(bacapp_tree, hf_BACnetRejectReason, tvb,
5391         offset++, 1, TRUE);
5392         return offset;
5393 }
5394
5395 static guint
5396 fAbortPDU(tvbuff_t *tvb, proto_tree *bacapp_tree, guint offset)
5397 {       /* BACnet-Abort-PDU */
5398         /* ASHRAE 135-2001 20.1.9 */
5399
5400         proto_item *tc;
5401         proto_tree *bacapp_tree_control;
5402
5403     tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, TRUE);
5404     bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
5405
5406     proto_tree_add_item(bacapp_tree, hf_bacapp_SRV, tvb, offset++, 1, TRUE);
5407     proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
5408         offset++, 1, TRUE);
5409     proto_tree_add_item(bacapp_tree, hf_BACnetAbortReason, tvb,
5410         offset++, 1, TRUE);
5411         return offset;
5412 }
5413
5414 void
5415 dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
5416 {
5417         gint8 tmp, bacapp_type;
5418         tvbuff_t *next_tvb;
5419         guint offset = 0;
5420     guint8 bacapp_service, bacapp_reason;
5421         proto_item *ti;
5422         proto_tree *bacapp_tree;
5423
5424         if (check_col(pinfo->cinfo, COL_PROTOCOL))
5425                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU");
5426         if (check_col(pinfo->cinfo, COL_INFO))
5427                 col_add_str(pinfo->cinfo, COL_INFO, "BACnet APDU ");
5428         
5429     tmp = (gint) tvb_get_guint8(tvb, 0);
5430         bacapp_type = (tmp >> 4) & 0x0f;
5431
5432         /* show some descriptive text in the INFO column */
5433         if (check_col(pinfo->cinfo, COL_INFO))
5434         {
5435                 col_clear(pinfo->cinfo, COL_INFO);
5436                 col_add_str(pinfo->cinfo, COL_INFO,
5437                         val_to_str(bacapp_type, BACnetTypeName, "#### unknown APDU ##### "));
5438                 switch (bacapp_type)
5439                 {
5440                         case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
5441                                 /* segmented messages have 2 additional bytes */
5442                                 if (tmp & BACAPP_SEGMENTED_REQUEST)
5443                                         bacapp_service = tvb_get_guint8(tvb, offset + 5);
5444                                 else
5445                                         bacapp_service = tvb_get_guint8(tvb, offset + 3);
5446                                 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
5447                                         val_to_str(bacapp_service, 
5448                                                 BACnetConfirmedServiceChoice,
5449                                                 bacapp_unknown_service_str));
5450                                 break;
5451                         case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:
5452                                 bacapp_service = tvb_get_guint8(tvb, offset + 1);
5453                                 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
5454                                         val_to_str(bacapp_service, 
5455                                                 BACnetUnconfirmedServiceChoice,
5456                                                 bacapp_unknown_service_str));
5457                                 break;
5458                         case BACAPP_TYPE_SIMPLE_ACK:
5459                                 bacapp_service = tvb_get_guint8(tvb, offset + 2);
5460                                 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
5461                                         val_to_str(bacapp_service, 
5462                                                 BACnetConfirmedServiceChoice,
5463                                                 bacapp_unknown_service_str));
5464                                 break;
5465                         case BACAPP_TYPE_COMPLEX_ACK:
5466                                 /* segmented messages have 2 additional bytes */
5467                                 if (tmp & BACAPP_SEGMENTED_REQUEST)
5468                                         bacapp_service = tvb_get_guint8(tvb, offset + 4);
5469                                 else
5470                                         bacapp_service = tvb_get_guint8(tvb, offset + 2);
5471                                 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
5472                                         val_to_str(bacapp_service, 
5473                                                 BACnetConfirmedServiceChoice,
5474                                                 bacapp_unknown_service_str));
5475                                 break;
5476                         case BACAPP_TYPE_SEGMENT_ACK:
5477                                 /* nothing more to add */
5478                                 break;
5479                         case BACAPP_TYPE_ERROR:
5480                                 bacapp_service = tvb_get_guint8(tvb, offset + 2);
5481                                 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
5482                                         val_to_str(bacapp_service, 
5483                                                 BACnetConfirmedServiceChoice,
5484                                                 bacapp_unknown_service_str));
5485                                 break;
5486                         case BACAPP_TYPE_REJECT:
5487                                 bacapp_reason = tvb_get_guint8(tvb, offset + 2);
5488                                 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", 
5489                                         val_to_split_str(bacapp_reason,
5490                                                 64,
5491                                                 BACnetRejectReason,
5492                                                 ASHRAE_Reserved_Fmt,
5493                                                 Vendor_Proprietary_Fmt));
5494                                 break;
5495                         case BACAPP_TYPE_ABORT:
5496                                 bacapp_reason = tvb_get_guint8(tvb, offset + 2);
5497                                 col_append_fstr(pinfo->cinfo, COL_INFO, ": %s",
5498                                         val_to_split_str(bacapp_reason,
5499                                                 64,
5500                                                 BACnetAbortReason,
5501                                                 ASHRAE_Reserved_Fmt,
5502                                                 Vendor_Proprietary_Fmt));
5503                                 break;
5504                         /* UNKNOWN */
5505                         default:
5506                                 /* nothing more to add */
5507                                 break;
5508                 }
5509         }
5510    
5511     if (tree) {
5512                 ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, FALSE);
5513                 bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
5514
5515                 /* ASHRAE 135-2001 20.1.1 */
5516         switch (bacapp_type) {
5517         case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:     /* BACnet-Confirmed-Service-Request */
5518                 offset = fConfirmedRequestPDU(tvb, bacapp_tree, offset);
5519                 break;
5520         case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:   /* BACnet-Unconfirmed-Request-PDU */
5521                 offset = fUnconfirmedRequestPDU(tvb, bacapp_tree, offset);
5522                 break;
5523         case BACAPP_TYPE_SIMPLE_ACK:    /* BACnet-Simple-Ack-PDU */
5524                 offset = fSimpleAckPDU(tvb, bacapp_tree, offset);
5525                 break;
5526         case BACAPP_TYPE_COMPLEX_ACK:   /* BACnet-Complex-Ack-PDU */
5527                 offset = fComplexAckPDU(tvb, bacapp_tree, offset);
5528                 break;
5529         case BACAPP_TYPE_SEGMENT_ACK:   /* BACnet-SegmentAck-PDU */
5530                 offset = fSegmentAckPDU(tvb, bacapp_tree, offset);
5531                 break;
5532         case BACAPP_TYPE_ERROR: /* BACnet-Error-PDU */
5533                 offset = fErrorPDU(tvb, bacapp_tree, offset);
5534                 break;
5535         case BACAPP_TYPE_REJECT:        /* BACnet-Reject-PDU */
5536                 offset = fRejectPDU(tvb, bacapp_tree, offset);
5537                 break;
5538         case BACAPP_TYPE_ABORT: /* BACnet-Abort-PDU */
5539                 offset = fAbortPDU(tvb, bacapp_tree, offset);
5540                 break;
5541         }
5542     }
5543
5544         next_tvb = tvb_new_subset(tvb,offset,-1,tvb_length_remaining(tvb,offset));
5545         call_dissector(data_handle,next_tvb, pinfo, tree);
5546 }
5547
5548 void
5549 proto_register_bacapp(void)
5550 {
5551         static hf_register_info hf[] = {
5552                 { &hf_bacapp_type,
5553                         { "APDU Type",           "bacapp.type",
5554                         FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, "APDU Type", HFILL }
5555                 },
5556                 { &hf_bacapp_pduflags,
5557                         { "PDU Flags",                  "bacapp.pduflags",
5558                         FT_UINT8, BASE_HEX, NULL, 0x0f, "PDU Flags", HFILL }
5559                 },
5560                 { &hf_bacapp_SEG,
5561                         { "Segmented Request",           "bacapp.segmented_request",
5562                         FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, "Segmented Request", HFILL }
5563                 },
5564                 { &hf_bacapp_MOR,
5565                         { "More Segments",           "bacapp.more_segments",
5566                         FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL }
5567                 },
5568                 { &hf_bacapp_SA,
5569                         { "SA",           "bacapp.SA",
5570                         FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL }
5571                 },
5572                 { &hf_bacapp_max_adpu_size,
5573                         { "Size of Maximum ADPU accepted",           "bacapp.max_adpu_size",
5574                         FT_UINT8, BASE_DEC, VALS(BACnetMaxAPDULengthAccepted), 0x0f, "Size of Maximum ADPU accepted", HFILL }
5575                 },
5576                 { &hf_bacapp_response_segments,
5577                         { "Max Response Segments accepted",           "bacapp.response_segments",
5578                         FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0x70, "Max Response Segments accepted", HFILL }
5579                 },
5580                 { &hf_bacapp_objectType,
5581                         { "Object Type",           "bacapp.objectType",
5582                         FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, "Object Type", HFILL }
5583                 },
5584                 { &hf_bacapp_instanceNumber,
5585                         { "Instance Number",           "bacapp.instance_number",
5586                         FT_UINT32, BASE_DEC, NULL, 0x003fffff, "Instance Number", HFILL }
5587                 },
5588                 { &hf_bacapp_invoke_id,
5589                         { "Invoke ID",           "bacapp.invoke_id",
5590                         FT_UINT8, BASE_DEC, NULL, 0, "Invoke ID", HFILL }
5591                 },
5592                 { &hf_bacapp_sequence_number,
5593                         { "Sequence Number",           "bacapp.sequence_number",
5594                         FT_UINT8, BASE_DEC, NULL, 0, "Sequence Number", HFILL }
5595                 },
5596                 { &hf_bacapp_window_size,
5597                         { "Proposed Window Size",           "bacapp.window_size",
5598                         FT_UINT8, BASE_DEC, NULL, 0, "Proposed Window Size", HFILL }
5599                 },
5600                 { &hf_bacapp_service,
5601                         { "Service Choice",           "bacapp.confirmed_service",
5602                         FT_UINT8, BASE_DEC, VALS(BACnetConfirmedServiceChoice), 0x00, "Service Choice", HFILL }
5603                 },
5604                 { &hf_bacapp_uservice,
5605                         { "Unconfirmed Service Choice",           "bacapp.unconfirmed_service",
5606                         FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, "Unconfirmed Service Choice", HFILL }
5607                 },
5608                 { &hf_bacapp_NAK,
5609                         { "NAK",           "bacapp.NAK",
5610                         FT_BOOLEAN, 8, NULL, 0x02, "negativ ACK", HFILL }
5611                 },
5612                 { &hf_bacapp_SRV,
5613                         { "SRV",           "bacapp.SRV",
5614                         FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL }
5615                 },
5616                 { &hf_BACnetRejectReason,
5617                         { "Reject Reason",           "bacapp.reject_reason",
5618                         FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, "Reject Reason", HFILL }
5619                 },
5620                 { &hf_BACnetAbortReason,
5621                         { "Abort Reason",           "bacapp.abort_reason",
5622                         FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 0x00, "Abort Reason", HFILL }
5623                 },
5624                 { &hf_bacapp_vpart,
5625                         { "BACnet APDU variable part:",           "bacapp.variable_part",
5626                         FT_NONE, 0, NULL, 0, "BACnet APDU variable part", HFILL }
5627                 },
5628                 { &hf_bacapp_tag,
5629                         { "BACnet Tag",
5630                         "bacapp.tag",
5631                         FT_BYTES, BASE_HEX, NULL, 0,
5632                         "BACnet Tag", HFILL }
5633                 },
5634                 { &hf_BACnetApplicationTagNumber,
5635                         { "Application Tag Number",
5636                         "bacapp.application_tag_number",
5637                         FT_UINT8, BASE_DEC, VALS(&BACnetApplicationTagNumber), 0xF0,
5638                         "Application Tag Number", HFILL }
5639                 },
5640                 { &hf_BACnetContextTagNumber,
5641                         { "Context Tag Number",
5642                         "bacapp.context_tag_number",
5643                         FT_UINT8, BASE_DEC, NULL, 0xF0,
5644                         "Context Tag Number", HFILL }
5645                 },
5646                 { &hf_BACnetExtendedTagNumber,
5647                         { "Extended Tag Number",
5648                         "bacapp.extended_tag_number",
5649                         FT_UINT8, BASE_DEC, NULL, 0,
5650                         "Extended Tag Number", HFILL }
5651                 },
5652                 { &hf_BACnetNamedTag,
5653                         { "Named Tag",
5654                         "bacapp.named_tag",
5655                         FT_UINT8, BASE_DEC, VALS(&BACnetTagNames), 0x07,
5656                         "Named Tag", HFILL }
5657                 },
5658                 { &hf_BACnetCharacterSet,
5659                         { "String Character Set",
5660                         "bacapp.string_character_set",
5661                         FT_UINT8, BASE_DEC, VALS(&BACnetCharacterSet),0,
5662                         "String Character Set", HFILL }
5663                 },
5664                 { &hf_BACnetTagClass,
5665                         { "Tag Class",           "bacapp.tag_class",
5666                         FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, "Tag Class", HFILL }
5667                 },
5668                 { &hf_bacapp_tag_lvt,
5669                         { "Length Value Type",
5670                         "bacapp.LVT",
5671                         FT_UINT8, BASE_DEC, NULL, 0,
5672                         "Length Value Type", HFILL }
5673                 },
5674                 { &hf_bacapp_tag_value8,
5675                         { "Tag Value",
5676                         "bacapp.tag_value8",
5677                         FT_UINT8, BASE_DEC, NULL, 0,
5678                         "Tag Value", HFILL }
5679                 },
5680                 { &hf_bacapp_tag_value16,
5681                         { "Tag Value 16-bit",
5682                         "bacapp.tag_value16",
5683                         FT_UINT16, BASE_DEC, NULL, 0,
5684                         "Tag Value 16-bit", HFILL }
5685                 },
5686                 { &hf_bacapp_tag_value32,
5687                         { "Tag Value 32-bit",
5688                         "bacapp.tag_value32",
5689                         FT_UINT32, BASE_DEC, NULL, 0,
5690                         "Tag Value 32-bit", HFILL }
5691                 },
5692                 { &hf_bacapp_tag_ProcessId,
5693                         { "ProcessIdentifier",           "bacapp.processId",
5694                         FT_UINT32, BASE_DEC, NULL, 0, "Process Identifier", HFILL }
5695                 },
5696                 { &hf_bacapp_tag_initiatingObjectType,
5697                         { "ObjectType",           "bacapp.objectType",
5698                         FT_UINT16, BASE_DEC, VALS(BACnetObjectType), 0x00, "Object Type", HFILL }
5699                 },
5700         };
5701         static gint *ett[] = {
5702                 &ett_bacapp,
5703                 &ett_bacapp_control,
5704                 &ett_bacapp_tag,
5705                 &ett_bacapp_list,
5706                 &ett_bacapp_value,
5707         };
5708         proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU",
5709             "BACapp", "bacapp");
5710
5711         proto_register_field_array(proto_bacapp, hf, array_length(hf));
5712         proto_register_subtree_array(ett, array_length(ett));
5713         register_dissector("bacapp", dissect_bacapp, proto_bacapp);
5714
5715 }
5716
5717 void
5718 proto_reg_handoff_bacapp(void)
5719 {
5720         data_handle = find_dissector("data");
5721 }
5722
5723 guint32
5724 fConvertXXXtoUTF8 (const guint8 *in, size_t *inbytesleft, guint8 *out, size_t *outbytesleft, const gchar *fromcoding)
5725 {  /* I don't want to let in and out be modified */
5726 #ifdef HAVE_CONFIG_H
5727 #if HAVE_ICONV_H
5728         guint32 i; 
5729         iconv_t icd;
5730         const guint8 *inp = in;
5731         guint8 *outp = out;
5732         const guint8 **inpp = &inp;
5733         guint8 **outpp = &outp;
5734      
5735     if ((icd = iconv_open ("UTF-8", fromcoding)) != (iconv_t) -1) {
5736         i = iconv (icd, (char**) inpp, inbytesleft, (char**) outpp, outbytesleft);
5737                 *outpp[0] = '\0';
5738         iconv_close (icd);
5739         return i;
5740     }
5741
5742 #endif
5743 #endif
5744
5745     memcpy (out, in, *inbytesleft);
5746     out[*inbytesleft] = '\0';
5747         *outbytesleft -= *inbytesleft;
5748     *inbytesleft = 0;
5749
5750     return 0;
5751 }
5752