Fixed some coding errors:
[metze/wireshark/wip.git] / epan / dissectors / packet-bacapp.c
1 /* packet-bacapp.c
2  * Routines for BACnet (APDU) dissection
3  * Copyright 2001, Hartmut Mueller <hartmut[AT]abmlinux.org>, FH Dortmund
4  * Enhanced by Steve Karg, 2005, <skarg[AT]users.sourceforge.net>, Atlanta
5  * Enhanced by Herbert Lischka, 2005, <lischka[AT]kieback-peter.de>, Berlin
6  * Enhanced by Felix Kraemer, 2010, <sauter-cumulus[AT]de.sauter-bc.com>,
7  *      Sauter-Cumulus GmbH, Freiburg
8  *
9  * $Id$
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald[AT]wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * Copied from README.developer,v 1.23
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <glib.h>
37
38 #include <epan/packet.h>
39 #include <epan/reassemble.h>
40 #include <epan/expert.h>
41 #include <epan/stats_tree.h>
42 #include "packet-bacapp.h"
43
44 static int bacapp_tap = -1;
45
46 /* formerly bacapp.h  contains definitions and forward declarations */
47
48 #ifndef FAULT
49 #define FAULT                   proto_tree_add_text(subtree, tvb, offset, tvb_length(tvb) - offset, "something is going wrong here !!"); \
50         offset = tvb_length(tvb);
51 #endif
52
53 /* BACnet PDU Types */
54 #define BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST 0
55 #define BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST 1
56 #define BACAPP_TYPE_SIMPLE_ACK 2
57 #define BACAPP_TYPE_COMPLEX_ACK 3
58 #define BACAPP_TYPE_SEGMENT_ACK 4
59 #define BACAPP_TYPE_ERROR 5
60 #define BACAPP_TYPE_REJECT 6
61 #define BACAPP_TYPE_ABORT 7
62 #define MAX_BACAPP_TYPE 8
63
64 #define BACAPP_SEGMENTED_REQUEST 0x08
65 #define BACAPP_MORE_SEGMENTS 0x04
66 #define BACAPP_SEGMENTED_RESPONSE 0x02
67 #define BACAPP_SEGMENT_NAK 0x02
68 #define BACAPP_SENT_BY 0x01
69
70
71 /**
72  * dissect_bacapp ::= CHOICE {
73  *  confirmed-request-PDU       [0] BACnet-Confirmed-Request-PDU,
74  *  unconfirmed-request-PDU     [1] BACnet-Unconfirmed-Request-PDU,
75  *  simpleACK-PDU               [2] BACnet-SimpleACK-PDU,
76  *  complexACK-PDU              [3] BACnet-ComplexACK-PDU,
77  *  segmentACK-PDU              [4] BACnet-SegmentACK-PDU,
78  *  error-PDU                   [5] BACnet-Error-PDU,
79  *  reject-PDU                  [6] BACnet-Reject-PDU,
80  *  abort-PDU                   [7] BACnet-Abort-PDU
81  * }
82  * @param tvb
83  * @param pinfo
84  * @param tree
85  **/
86 static void
87 dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
88
89 /**
90  * ConfirmedRequest-PDU ::= SEQUENCE {
91  *      pdu-type                                        [0] Unsigned (0..15), -- 0 for this PDU Type
92  *  segmentedMessage                    [1] BOOLEAN,
93  *  moreFollows                                 [2] BOOLEAN,
94  *  segmented-response-accepted [3] BOOLEAN,
95  *  reserved                                    [4] Unsigned (0..3), -- must be set zero
96  *  max-segments-accepted               [5] Unsigned (0..7), -- as per 20.1.2.4
97  *  max-APDU-length-accepted    [5] Unsigned (0..15), -- as per 20.1.2.5
98  *  invokeID                                    [6] Unsigned (0..255),
99  *  sequence-number                             [7] Unsigned (0..255) OPTIONAL, -- only if segmented msg
100  *  proposed-window-size                [8] Unsigned (0..127) OPTIONAL, -- only if segmented msg
101  *  service-choice                              [9] BACnetConfirmedServiceChoice,
102  *  service-request                             [10] BACnet-Confirmed-Service-Request OPTIONAL
103  * }
104  * @param tvb
105  * @param pinfo
106  * @param tree
107  * @param offset
108  * @return modified offset
109  */
110 static guint
111 fConfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
112
113 /**
114  * @param tvb
115  * @param pinfo
116  * @param tree
117  * @param offset
118  * @param ack - indocates whether working on request or ack
119  * @param svc - output variable to return service choice
120  * @param tt  - output varable to return service choice item
121  * @return modified offset
122  */
123 static guint
124 fStartConfirmed(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 ack,
125                                 gint *svc, proto_item **tt);
126
127 /**
128  * Unconfirmed-Request-PDU ::= SEQUENCE {
129  *      pdu-type                [0] Unsigned (0..15), -- 1 for this PDU type
130  *  reserved            [1] Unsigned (0..15), -- must be set zero
131  *  service-choice      [2] BACnetUnconfirmedServiceChoice,
132  *  service-request     [3] BACnetUnconfirmedServiceRequest -- Context-specific tags 0..3 are NOT used in header encoding
133  * }
134  * @param tvb
135  * @param pinfo
136  * @param tree
137  * @param offset
138  * @return modified offset
139  */
140 static guint
141 fUnconfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
142
143 /**
144  * SimpleACK-PDU ::= SEQUENCE {
145  *      pdu-type                [0] Unsigned (0..15), -- 2 for this PDU type
146  *  reserved            [1] Unsigned (0..15), -- must be set zero
147  *  invokeID            [2] Unsigned (0..255),
148  *  service-ACK-choice  [3] BACnetUnconfirmedServiceChoice -- Context-specific tags 0..3 are NOT used in header encoding
149  * }
150  * @param tvb
151  * @param pinfo
152  * @param tree
153  * @param offset
154  * @return modified offset
155  */
156 static guint
157 fSimpleAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
158
159 /**
160  * ComplexACK-PDU ::= SEQUENCE {
161  *      pdu-type                                [0] Unsigned (0..15), -- 3 for this PDU Type
162  *  segmentedMessage            [1] BOOLEAN,
163  *  moreFollows                         [2] BOOLEAN,
164  *  reserved                            [3] Unsigned (0..3), -- must be set zero
165  *  invokeID                            [4] Unsigned (0..255),
166  *  sequence-number                     [5] Unsigned (0..255) OPTIONAL, -- only if segmented msg
167  *  proposed-window-size        [6] Unsigned (0..127) OPTIONAL, -- only if segmented msg
168  *  service-ACK-choice          [7] BACnetConfirmedServiceChoice,
169  *  service-ACK                         [8] BACnet-Confirmed-Service-Request  -- Context-specific tags 0..8 are NOT used in header encoding
170  * }
171  * @param tvb
172  * @param pinfo
173  * @param tree
174  * @param offset
175  * @return modified offset
176  */
177 static guint
178 fComplexAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
179
180 /**
181  * SegmentACK-PDU ::= SEQUENCE {
182  *      pdu-type                                [0] Unsigned (0..15), -- 4 for this PDU Type
183  *  reserved                            [1] Unsigned (0..3), -- must be set zero
184  *  negative-ACK                        [2] BOOLEAN,
185  *  server                                      [3] BOOLEAN,
186  *  original-invokeID           [4] Unsigned (0..255),
187  *  sequence-number                     [5] Unsigned (0..255),
188  *  actual-window-size          [6] Unsigned (0..127)
189  * }
190  * @param tvb
191  * @param pinfo
192  * @param tree
193  * @param offset
194  * @return modified offset
195  */
196 static guint
197 fSegmentAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
198
199 /**
200  * Error-PDU ::= SEQUENCE {
201  *      pdu-type                                [0] Unsigned (0..15), -- 5 for this PDU Type
202  *  reserved                            [1] Unsigned (0..3), -- must be set zero
203  *  original-invokeID           [2] Unsigned (0..255),
204  *  error-choice                        [3] BACnetConfirmedServiceChoice,
205  *  error                                       [4] BACnet-Error
206  * }
207  * @param tvb
208  * @param pinfo
209  * @param tree
210  * @param offset
211  * @return modified offset
212  */
213 static guint
214 fErrorPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
215
216 /**
217  * Reject-PDU ::= SEQUENCE {
218  *      pdu-type                                [0] Unsigned (0..15), -- 6 for this PDU Type
219  *  reserved                            [1] Unsigned (0..3), -- must be set zero
220  *  original-invokeID           [2] Unsigned (0..255),
221  *  reject-reason                       [3] BACnetRejectReason
222  * }
223  * @param tvb
224  * @param pinfo
225  * @param tree
226  * @param offset
227  * @return modified offset
228  */
229 static guint
230 fRejectPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
231
232 /**
233  * Abort-PDU ::= SEQUENCE {
234  *      pdu-type                                [0] Unsigned (0..15), -- 7 for this PDU Type
235  *  reserved                            [1] Unsigned (0..3), -- must be set zero
236  *  server                                      [2] BOOLEAN,
237  *  original-invokeID           [3] Unsigned (0..255),
238  *  abort-reason                        [4] BACnetAbortReason
239  * }
240  * @param tvb
241  * @param pinfo
242  * @param tree
243  * @param offset
244  * @return modified offset
245  */
246 static guint
247 fAbortPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
248
249 /**
250  * 20.2.4, adds the label with max 64Bit unsigned Integer Value to tree
251  * @param tvb
252  * @param tree
253  * @param offset
254  * @param label
255  * @return modified offset
256  */
257 static guint
258 fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label);
259
260 /**
261  * 20.2.5, adds the label with max 64Bit signed Integer Value to tree
262  * @param tvb
263  * @param tree
264  * @param offset
265  * @param label
266  * @return modified offset
267  */
268 static guint
269 fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label);
270
271 /**
272  * 20.2.8, adds the label with Octet String to tree; if lvt == 0 then lvt = restOfFrame
273  * @param tvb
274  * @param tree
275  * @param offset
276  * @param label
277  * @param lvt length of String
278  * @return modified offset
279  */
280 static guint
281 fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, guint32 lvt);
282
283 /**
284  * 20.2.12, adds the label with Date Value to tree
285  * @param tvb
286  * @param tree
287  * @param offset
288  * @param label
289  * @return modified offset
290  */
291 static guint
292 fDate    (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label);
293
294 /**
295  * 20.2.13, adds the label with Time Value to tree
296  * @param tvb
297  * @param tree
298  * @param offset
299  * @param label
300  * @return modified offset
301  */
302 static guint
303 fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label);
304
305 /**
306  * 20.2.14, adds Object Identifier to tree
307  * use BIG ENDIAN: Bits 31..22 Object Type, Bits 21..0 Instance Number
308  * @param tvb
309  * @param pinfo
310  * @param tree
311  * @param offset
312  * @return modified offset
313  */
314 static guint
315 fObjectIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
316
317 /**
318  * BACnet-Confirmed-Service-Request ::= CHOICE {
319  * }
320  * @param tvb
321  * @param pinfo
322  * @param tree
323  * @param offset
324  * @param service_choice
325  * @return offset
326  */
327 static guint
328 fConfirmedServiceRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice);
329
330 /**
331  * BACnet-Confirmed-Service-ACK ::= CHOICE {
332  * }
333  * @param tvb
334  * @param pinfo
335  * @param tree
336  * @param offset
337  * @param service_choice
338  * @return offset
339  */
340 static guint
341 fConfirmedServiceAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice);
342
343 /**
344  * AcknowledgeAlarm-Request ::= SEQUENCE {
345  *      acknowledgingProcessIdentifier  [0]     Unsigned32,
346  *      eventObjectIdentifier   [1] BACnetObjectIdentifer,
347  *      eventStateAcknowledge   [2] BACnetEventState,
348  *      timeStamp       [3] BACnetTimeStamp,
349  *      acknowledgementSource   [4] Character String,
350  *  timeOfAcknowledgement       [5] BACnetTimeStamp
351  * }
352  * @param tvb
353  * @param pinfo
354  * @param tree
355  * @param offset
356  * @return modified offset
357  */
358 static guint
359 fAcknowledgeAlarmRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
360
361 /**
362  * ConfirmedCOVNotification-Request ::= SEQUENCE {
363  *      subscriberProcessIdentifier     [0]     Unsigned32,
364  *      initiatingDeviceIdentifier      [1] BACnetObjectIdentifer,
365  *      monitoredObjectIdentifier       [2] BACnetObjectIdentifer,
366  *      timeRemaining   [3] unsigned,
367  *      listOfValues    [4] SEQUENCE OF BACnetPropertyValues
368  * }
369  * @param tvb
370  * @param pinfo
371  * @param tree
372  * @param offset
373  * @return modified offset
374  */
375 static guint
376 fConfirmedCOVNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
377
378 /**
379  * ConfirmedEventNotification-Request ::= SEQUENCE {
380  *      ProcessIdentifier       [0]     Unsigned32,
381  *      initiatingDeviceIdentifier      [1] BACnetObjectIdentifer,
382  *      eventObjectIdentifier   [2] BACnetObjectIdentifer,
383  *      timeStamp       [3] BACnetTimeStamp,
384  *      notificationClass       [4] unsigned,
385  *      priority        [5] unsigned8,
386  *      eventType       [6] BACnetEventType,
387  *      messageText     [7] CharacterString OPTIONAL,
388  *      notifyType      [8] BACnetNotifyType,
389  *      ackRequired     [9] BOOLEAN OPTIONAL,
390  *      fromState       [10] BACnetEventState OPTIONAL,
391  *      toState [11] BACnetEventState,
392  *      eventValues     [12] BACnetNotificationParameters OPTIONAL
393  * }
394  * @param tvb
395  * @param pinfo
396  * @param tree
397  * @param offset
398  * @return modified offset
399  */
400 static guint
401 fConfirmedEventNotificationRequest (tvbuff_t *tvb, packet_info *pinfo,  proto_tree *tree, guint offset);
402
403 /**
404  * GetAlarmSummary-ACK ::= SEQUENCE OF SEQUENCE {
405  *      objectIdentifier        BACnetObjectIdentifer,
406  *      alarmState      BACnetEventState,
407  *      acknowledgedTransitions  BACnetEventTransitionBits
408  * }
409  * @param tvb
410  * @param pinfo
411  * @param tree
412  * @param offset
413  * @return modified offset
414  */
415 static guint
416 fGetAlarmSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
417
418 /**
419  * GetEnrollmentSummary-Request ::= SEQUENCE {
420  *      acknowledgmentFilter    [0]     ENUMERATED {
421  *      all (0),
422  *      acked   (1),
423  *      not-acked   (2)
424  *      },
425  *      enrollmentFilter        [1] BACnetRecipientProcess OPTIONAL,
426  *      eventStateFilter        [2] ENUMERATED {
427  *      offnormal   (0),
428  *      fault   (1),
429  *      normal  (2),
430  *      all (3),
431  *      active  (4)
432  *      },
433  *      eventTypeFilter [3] BACnetEventType OPTIONAL,
434  *      priorityFilter  [4] SEQUENCE {
435  *      minPriority [0] Unsigned8,
436  *      maxPriority [1] Unsigned8
437  *      } OPTIONAL,
438  *  notificationClassFilter     [5] Unsigned OPTIONAL
439  * }
440  * @param tvb
441  * @param pinfo
442  * @param tree
443  * @param offset
444  * @return modified offset
445  */
446 static guint
447 fGetEnrollmentSummaryRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
448
449 /**
450  * GetEnrollmentSummary-ACK ::= SEQUENCE OF SEQUENCE {
451  *      objectIdentifier        BACnetObjectIdentifer,
452  *      eventType       BACnetEventType,
453  *      eventState      BACnetEventState,
454  *      priority    Unsigned8,
455  *  notificationClass   Unsigned OPTIONAL
456  * }
457  * @param tvb
458  * @param pinfo
459  * @param tree
460  * @param offset
461  * @return modified offset
462  */
463 static guint
464 fGetEnrollmentSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
465
466 /**
467  * GetEventInformation-Request ::= SEQUENCE {
468  *      lastReceivedObjectIdentifier    [0] BACnetObjectIdentifer
469  * }
470  * @param tvb
471  * @param pinfo
472  * @param tree
473  * @param offset
474  * @return modified offset
475  */
476 static guint
477 fGetEventInformationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
478
479 /**
480  * GetEventInformation-ACK ::= SEQUENCE {
481  *      listOfEventSummaries    [0] listOfEventSummaries,
482  *  moreEvents  [1] BOOLEAN
483  * }
484  * @param tvb
485  * @param pinfo
486  * @param tree
487  * @param offset
488  * @return modified offset
489  */
490 static guint
491 fGetEventInformationACK (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
492
493 /**
494  * LifeSafetyOperation-Request ::= SEQUENCE {
495  *      requestingProcessIdentifier     [0]     Unsigned32
496  *      requestingSource        [1] CharacterString
497  *      request [2] BACnetLifeSafetyOperation
498  *      objectIdentifier        [3] BACnetObjectIdentifier OPTIONAL
499  * }
500  * @param tvb
501  * @param pinfo
502  * @param tree
503  * @param offset
504  * @return modified offset
505  */
506 static guint
507 fLifeSafetyOperationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label);
508
509 /**
510  * SubscribeCOV-Request ::= SEQUENCE {
511  *      subscriberProcessIdentifier     [0]     Unsigned32
512  *      monitoredObjectIdentifier       [1] BACnetObjectIdentifier
513  *      issueConfirmedNotifications     [2] BOOLEAN OPTIONAL
514  *      lifetime        [3] Unsigned OPTIONAL
515  * }
516  * @param tvb
517  * @param pinfo
518  * @param tree
519  * @param offset
520  * @param label
521  * @param src
522  * @return modified offset
523  */
524 static guint
525 fSubscribeCOVRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
526
527 /**
528  * SubscribeCOVProperty-Request ::= SEQUENCE {
529  *      subscriberProcessIdentifier     [0]     Unsigned32
530  *      monitoredObjectIdentifier       [1] BACnetObjectIdentifier
531  *      issueConfirmedNotifications     [2] BOOLEAN OPTIONAL
532  *      lifetime        [3] Unsigned OPTIONAL
533  *      monitoredPropertyIdentifier     [4] BACnetPropertyReference OPTIONAL
534  *      covIncrement    [5] Unsigned OPTIONAL
535  * }
536  * @param tvb
537  * @param pinfo
538  * @param tree
539  * @param offset
540  * @return modified offset
541  */
542 static guint
543 fSubscribeCOVPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
544
545 /**
546  * AtomicReadFile-Request ::= SEQUENCE {
547  *      fileIdentifier  BACnetObjectIdentifier,
548  *  accessMethod        CHOICE {
549  *      streamAccess    [0] SEQUENCE {
550  *              fileStartPosition       INTEGER,
551  *                      requestedOctetCount     Unsigned
552  *                      },
553  *              recordAccess    [1] SEQUENCE {
554  *                      fileStartRecord INTEGER,
555  *                      requestedRecordCount    Unsigned
556  *                      }
557  *              }
558  * }
559  * @param tvb
560  * @param pinfo
561  * @param tree
562  * @param offset
563  * @return modified offset
564  */
565 static guint
566 fAtomicReadFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
567
568 /**
569  * AtomicWriteFile-ACK ::= SEQUENCE {
570  *      endOfFile       BOOLEAN,
571  *  accessMethod        CHOICE {
572  *      streamAccess    [0] SEQUENCE {
573  *              fileStartPosition       INTEGER,
574  *                      fileData        OCTET STRING
575  *                      },
576  *              recordAccess    [1] SEQUENCE {
577  *                      fileStartRecord INTEGER,
578  *                      returnedRecordCount     Unsigned,
579  *                      fileRecordData  SEQUENCE OF OCTET STRING
580  *                      }
581  *              }
582  * }
583  * @param tvb
584  * @param pinfo
585  * @param tree
586  * @param offset
587  * @return modified offset
588  */
589 static guint
590 fAtomicReadFileAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
591
592 /**
593  * AtomicWriteFile-Request ::= SEQUENCE {
594  *      fileIdentifier  BACnetObjectIdentifier,
595  *  accessMethod        CHOICE {
596  *      streamAccess    [0] SEQUENCE {
597  *              fileStartPosition       INTEGER,
598  *                      fileData        OCTET STRING
599  *                      },
600  *              recordAccess    [1] SEQUENCE {
601  *                      fileStartRecord INTEGER,
602  *                      recordCount     Unsigned,
603  *                      fileRecordData  SEQUENCE OF OCTET STRING
604  *                      }
605  *              }
606  * }
607  * @param tvb
608  * @param pinfo
609  * @param tree
610  * @param offset
611  * @return modified offset
612  */
613 static guint
614 fAtomicWriteFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
615
616 /**
617  * AtomicWriteFile-ACK ::= SEQUENCE {
618  *              fileStartPosition       [0] INTEGER,
619  *              fileStartRecord [1] INTEGER,
620  * }
621  * @param tvb
622  * @param tree
623  * @param offset
624  * @return modified offset
625  */
626 static guint
627 fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
628
629 /**
630  * AddListElement-Request ::= SEQUENCE {
631  *      objectIdentifier        [0] BACnetObjectIdentifier,
632  *  propertyIdentifier  [1] BACnetPropertyIdentifier,
633  *  propertyArrayIndex  [2] Unsigned OPTIONAL, -- used only with array datatype
634  *  listOfElements  [3] ABSTRACT-SYNTAX.&Type
635  * }
636  * @param tvb
637  * @param pinfo
638  * @param tree
639  * @param offset
640  * @return modified offset
641  */
642 static guint
643 fAddListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
644
645 /**
646  * CreateObject-Request ::= SEQUENCE {
647  *      objectSpecifier [0] ObjectSpecifier,
648  *  listOfInitialValues [1] SEQUENCE OF BACnetPropertyValue OPTIONAL
649  * }
650  * @param tvb
651  * @param pinfo
652  * @param tree
653  * @param offset
654  * @return modified offset
655  */
656 static guint
657 fCreateObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset);
658
659 /**
660  * CreateObject-Request ::= BACnetObjectIdentifier
661  * @param tvb
662  * @param pinfo
663  * @param tree
664  * @param offset
665  * @return modified offset
666  */
667 static guint
668 fCreateObjectAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
669
670 /**
671  * DeleteObject-Request ::= SEQUENCE {
672  *      ObjectIdentifier        BACnetObjectIdentifer
673  * }
674  * @param tvb
675  * @param pinfo
676  * @param tree
677  * @param offset
678  * @return modified offset
679  */
680 static guint
681 fDeleteObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
682
683 /**
684  * ReadProperty-Request ::= SEQUENCE {
685  *      objectIdentifier        [0]     BACnetObjectIdentifier,
686  *      propertyIdentifier      [1] BACnetPropertyIdentifier,
687  *      propertyArrayIndex      [2] Unsigned OPTIONAL, -- used only with array datatype
688  * }
689  * @param tvb
690  * @param pinfo
691  * @param tree
692  * @param offset
693  * @return modified offset
694  */
695 static guint
696 fReadPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
697
698 /**
699  * ReadProperty-ACK ::= SEQUENCE {
700  *      objectIdentifier        [0]     BACnetObjectIdentifier,
701  *      propertyIdentifier      [1] BACnetPropertyIdentifier,
702  *      propertyArrayIndex      [2] Unsigned OPTIONAL, -- used only with array datatype
703  *      propertyValue   [3] ABSTRACT-SYNTAX.&Type
704  * }
705  * @param tvb
706  * @param pinfo
707  * @param tree
708  * @param offset
709  * @return modified offset
710  */
711 static guint
712 fReadPropertyAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
713
714 /**
715  * ReadPropertyConditional-Request ::= SEQUENCE {
716  *      objectSelectionCriteria [0] objectSelectionCriteria,
717  *      listOfPropertyReferences        [1] SEQUENCE OF BACnetPropertyReference OPTIONAL
718  * }
719  * @param tvb
720  * @param pinfo
721  * @param tree
722  * @param offset
723  * @return modified offset
724  */
725 static guint
726 fReadPropertyConditionalRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset);
727
728 /**
729  * ReadPropertyConditional-ACK ::= SEQUENCE {
730  *      listOfPReadAccessResults        SEQUENCE OF ReadAccessResult OPTIONAL
731  * }
732  * @param tvb
733  * @param pinfo
734  * @param tree
735  * @param offset
736  * @return modified offset
737  */
738 static guint
739 fReadPropertyConditionalAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
740
741 /**
742  * ReadPropertyMultiple-Request ::= SEQUENCE {
743  *  listOfReadAccessSpecs       SEQUENCE OF ReadAccessSpecification
744  * }
745  * @param tvb
746  * @param pinfo
747  * @param tree
748  * @param offset
749  * @return offset modified
750  */
751 static guint
752 fReadPropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset);
753
754 /**
755  * ReadPropertyMultiple-Ack ::= SEQUENCE {
756  *  listOfReadAccessResults     SEQUENCE OF ReadAccessResult
757  * }
758  * @param tvb
759  * @parma pinfo
760  * @param tree
761  * @param offset
762  * @return offset modified
763  */
764 static guint
765 fReadPropertyMultipleAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
766
767 /**
768  * ReadRange-Request ::= SEQUENCE {
769  *      objectIdentifier        [0] BACnetObjectIdentifier,
770  *  propertyIdentifier  [1] BACnetPropertyIdentifier,
771  *  propertyArrayIndex  [2] Unsigned OPTIONAL, -- used only with array datatype
772  *      range   CHOICE {
773  *              byPosition      [3] SEQUENCE {
774  *                      referencedIndex Unsigned,
775  *                      count INTEGER
776  *                      },
777  *              byTime  [4] SEQUENCE {
778  *                      referenceTime BACnetDateTime,
779  *                      count INTEGER
780  *                      },
781  *              timeRange       [5] SEQUENCE {
782  *                      beginningTime BACnetDateTime,
783  *                      endingTime BACnetDateTime
784  *                      },
785  *              } OPTIONAL
786  * }
787  * @param tvb
788  * @param pinfo
789  * @param tree
790  * @param offset
791  * @return modified offset
792  */
793 static guint
794 fReadRangeRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
795
796 /**
797  * ReadRange-ACK ::= SEQUENCE {
798  *      objectIdentifier        [0] BACnetObjectIdentifier,
799  *  propertyIdentifier  [1] BACnetPropertyIdentifier,
800  *  propertyArrayIndex  [2] Unsigned OPTIONAL, -- used only with array datatype
801  *  resultFlags [3] BACnetResultFlags,
802  *  itemCount   [4] Unsigned,
803  *  itemData    [5] SEQUENCE OF ABSTRACT-SYNTAX.&Type
804  * }
805  * @param tvb
806  * @param pinfo
807  * @param tree
808  * @param offset
809  * @return modified offset
810  */
811 static guint
812 fReadRangeAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
813
814 /**
815  * RemoveListElement-Request ::= SEQUENCE {
816  *      objectIdentifier        [0]     BACnetObjectIdentifier,
817  *      propertyIdentifier      [1] BACnetPropertyIdentifier,
818  *      propertyArrayIndex      [2] Unsigned OPTIONAL, -- used only with array datatype
819  *      listOfElements  [3] ABSTRACT-SYNTAX.&Type
820  * }
821  * @param tvb
822  * @param pinfo
823  * @param tree
824  * @param offset
825  * @return modified offset
826  */
827 static guint
828 fRemoveListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
829
830 /**
831  * WriteProperty-Request ::= SEQUENCE {
832  *      objectIdentifier        [0]     BACnetObjectIdentifier,
833  *      propertyIdentifier      [1] BACnetPropertyIdentifier,
834  *      propertyArrayIndex      [2] Unsigned OPTIONAL, -- used only with array datatype
835  *      propertyValue   [3] ABSTRACT-SYNTAX.&Type
836  *  priority    [4] Unsigned8 (1..16) OPTIONAL --used only when property is commandable
837  * }
838  * @param tvb
839  * @param pinfo
840  * @param tree
841  * @param offset
842  * @return modified offset
843  */
844 static guint
845 fWritePropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
846
847 /**
848  * WritePropertyMultiple-Request ::= SEQUENCE {
849  *      listOfWriteAccessSpecifications SEQUENCE OF WriteAccessSpecification
850  * }
851  * @param tvb
852  * @param pinfo
853  * @param tree
854  * @param offset
855  * @return modified offset
856  */
857 static guint
858 fWritePropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
859
860 /**
861  * DeviceCommunicationControl-Request ::= SEQUENCE {
862  *      timeDuration    [0] Unsigned16 OPTIONAL,
863  *  enable-disable      [1] ENUMERATED {
864  *              enable (0),
865  *              disable (1)
866  *              },
867  *  password    [2] CharacterString (SIZE(1..20)) OPTIONAL
868  * }
869  * @param tvb
870  * @param tree
871  * @param offset
872  * @return modified offset
873  */
874 static guint
875 fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
876
877 /**
878  * ConfirmedPrivateTransfer-Request ::= SEQUENCE {
879  *      vendorID        [0]     Unsigned,
880  *      serviceNumber   [1] Unsigned,
881  *      serviceParameters       [2] ABSTRACT-SYNTAX.&Type OPTIONAL
882  * }
883  * @param tvb
884  * @param pinfo
885  * @param tree
886  * @param offset
887  * @return modified offset
888  */
889 static guint
890 fConfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
891
892 /**
893  * ConfirmedPrivateTransfer-ACK ::= SEQUENCE {
894  *      vendorID        [0]     Unsigned,
895  *      serviceNumber   [1] Unsigned,
896  *      resultBlock     [2] ABSTRACT-SYNTAX.&Type OPTIONAL
897  * }
898  * @param tvb
899  * @param pinfo
900  * @param tree
901  * @param offset
902  * @return modified offset
903  */
904 static guint
905 fConfirmedPrivateTransferAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
906
907 /**
908  * ConfirmedTextMessage-Request ::=  SEQUENCE {
909  *  textMessageSourceDevice [0] BACnetObjectIdentifier,
910  *  messageClass [1] CHOICE {
911  *      numeric [0] Unsigned,
912  *      character [1] CharacterString
913  *      } OPTIONAL,
914  *  messagePriority [2] ENUMERATED {
915  *      normal (0),
916  *      urgent (1)
917  *      },
918  *  message [3] CharacterString
919  * }
920  * @param tvb
921  * @param pinfo
922  * @param tree
923  * @param offset
924  * @return modified offset
925  */
926 static guint
927 fConfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
928
929 /**
930  * ReinitializeDevice-Request ::= SEQUENCE {
931  *  reinitializedStateOfDevice  [0] ENUMERATED {
932  *              coldstart (0),
933  *              warmstart (1),
934  *              startbackup (2),
935  *              endbackup (3),
936  *              startrestore (4),
937  *              endrestore (5),
938  *              abortrestor (6)
939  *              },
940  *  password    [1] CharacterString (SIZE(1..20)) OPTIONAL
941  * }
942  * @param tvb
943  * @param tree
944  * @param offset
945  * @return modified offset
946  */
947 static guint
948 fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset);
949
950 /**
951  * VTOpen-Request ::= SEQUENCE {
952  *  vtClass     BACnetVTClass,
953  *  localVTSessionIdentifier    Unsigned8
954  * }
955  * @param tvb
956  * @param pinfo
957  * @param tree
958  * @param offset
959  * @return modified offset
960  */
961 static guint
962 fVtOpenRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
963
964 /**
965  * VTOpen-ACK ::= SEQUENCE {
966  *  remoteVTSessionIdentifier   Unsigned8
967  * }
968  * @param tvb
969  * @param pinfo
970  * @param tree
971  * @param offset
972  * @return modified offset
973  */
974 static guint
975 fVtOpenAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
976
977 /**
978  * VTClose-Request ::= SEQUENCE {
979  *  listOfRemoteVTSessionIdentifiers    SEQUENCE OF Unsigned8
980  * }
981  * @param tvb
982  * @param pinfo
983  * @param tree
984  * @param offset
985  * @return modified offset
986  */
987 static guint
988 fVtCloseRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
989
990 /**
991  * VTData-Request ::= SEQUENCE {
992  *  vtSessionIdentifier Unsigned8,
993  *  vtNewData   OCTET STRING,
994  *  vtDataFlag  Unsigned (0..1)
995  * }
996  * @param tvb
997  * @param pinfo
998  * @param tree
999  * @param offset
1000  * @return modified offset
1001  */
1002 static guint
1003 fVtDataRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1004
1005 /**
1006  * VTData-ACK ::= SEQUENCE {
1007  *  allNewDataAccepted  [0] BOOLEAN,
1008  *  acceptedOctetCount  [1] Unsigned OPTIONAL -- present only if allNewDataAccepted = FALSE
1009  * }
1010  * @param tvb
1011  * @param tree
1012  * @param offset
1013  * @return modified offset
1014  */
1015 static guint
1016 fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset);
1017
1018 /**
1019  * Authenticate-Request ::= SEQUENCE {
1020  *  pseudoRandomNumber  [0] Unsigned32,
1021  *  excpectedInvokeID   [1] Unsigned8 OPTIONAL,
1022  *  operatorName        [2] CharacterString OPTIONAL,
1023  *  operatorPassword    [3] CharacterString (SIZE(1..20)) OPTIONAL,
1024  *  startEncypheredSession      [4] BOOLEAN OPTIONAL
1025  * }
1026  * @param tvb
1027  * @param tree
1028  * @param offset
1029  * @return modified offset
1030  */
1031 static guint
1032 fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset);
1033
1034 /**
1035  * Authenticate-ACK ::= SEQUENCE {
1036  *  modifiedRandomNumber        Unsigned32,
1037  * }
1038  * @param tvb
1039  * @param pinfo
1040  * @param tree
1041  * @param offset
1042  * @return modified offset
1043  */
1044 static guint
1045 fAuthenticateAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1046
1047 /**
1048  * RequestKey-Request ::= SEQUENCE {
1049  *  requestingDeviceIdentifier  BACnetObjectIdentifier,
1050  *  requestingDeviceAddress     BACnetAddress,
1051  *  remoteDeviceIdentifier      BACnetObjectIdentifier,
1052  *  remoteDeviceAddress BACnetAddress
1053  * }
1054  * @param tvb
1055  * @param pinfo
1056  * @param tree
1057  * @param offset
1058  * @return modified offset
1059  */
1060 static guint
1061 fRequestKeyRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1062
1063 /**
1064  * Unconfirmed-Service-Request ::= CHOICE {
1065  * }
1066  * @param tvb
1067  * @param pinfo
1068  * @param tree
1069  * @param offset
1070  * @param service_choice
1071  * @return modified offset
1072  */
1073 static guint
1074 fUnconfirmedServiceRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice);
1075
1076 /**
1077  * UnconfirmedCOVNotification-Request ::= SEQUENCE {
1078  *      subscriberProcessIdentifier     [0]     Unsigned32,
1079  *      initiatingDeviceIdentifier      [1] BACnetObjectIdentifer,
1080  *      monitoredObjectIdentifier       [2] BACnetObjectIdentifer,
1081  *      timeRemaining   [3] unsigned,
1082  *      listOfValues    [4] SEQUENCE OF BACnetPropertyValues
1083  * }
1084  * @param tvb
1085  * @param pinfo
1086  * @param tree
1087  * @param offset
1088  * @return modified offset
1089  */
1090 static guint
1091 fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1092
1093 /**
1094  * UnconfirmedEventNotification-Request ::= SEQUENCE {
1095  *      ProcessIdentifier       [0]     Unsigned32,
1096  *      initiatingDeviceIdentifier      [1] BACnetObjectIdentifer,
1097  *      eventObjectIdentifier   [2] BACnetObjectIdentifer,
1098  *      timeStamp       [3] BACnetTimeStamp,
1099  *      notificationClass       [4] unsigned,
1100  *      priority        [5] unsigned8,
1101  *      eventType       [6] BACnetEventType,
1102  *      messageText     [7] CharacterString OPTIONAL,
1103  *      notifyType      [8] BACnetNotifyType,
1104  *      ackRequired     [9] BOOLEAN OPTIONAL,
1105  *      fromState       [10] BACnetEventState OPTIONAL,
1106  *      toState [11] BACnetEventState,
1107  *      eventValues     [12] BACnetNotificationParameters OPTIONAL
1108  * }
1109  * @param tvb
1110  * @param pinfo
1111  * @param tree
1112  * @param offset
1113  * @return modified offset
1114  */
1115 static guint
1116 fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1117
1118 /**
1119  * I-Am-Request ::= SEQUENCE {
1120  *      aAmDeviceIdentifier     BACnetObjectIdentifier,
1121  *  maxAPDULengthAccepted       Unsigned,
1122  *      segmentationSupported   BACnetSegmentation,
1123  *      vendorID        Unsigned
1124  * }
1125  * @param tvb
1126  * @param pinfo
1127  * @param tree
1128  * @param offset
1129  * @return modified offset
1130  */
1131 static guint
1132 fIAmRequest  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1133
1134
1135 /**
1136  * I-Have-Request ::= SEQUENCE {
1137  *      deviceIdentifier        BACnetObjectIdentifier,
1138  *  objectIdentifier    BACnetObjectIdentifier,
1139  *      objectName      CharacterString
1140  * }
1141  * @param tvb
1142  * @param pinfo
1143  * @param tree
1144  * @param offset
1145  * @return modified offset
1146  */
1147 static guint
1148 fIHaveRequest  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1149
1150 /**
1151  * UnconfirmedPrivateTransfer-Request ::= SEQUENCE {
1152  *      vendorID        [0]     Unsigned,
1153  *      serviceNumber   [1] Unsigned,
1154  *      serviceParameters       [2] ABSTRACT-SYNTAX.&Type OPTIONAL
1155  * }
1156  * @param tvb
1157  * @param pinfo
1158  * @param tree
1159  * @param offset
1160  * @return modified offset
1161  */
1162 static guint
1163 fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1164
1165 /**
1166  * UnconfirmedTextMessage-Request ::=  SEQUENCE {
1167  *  textMessageSourceDevice [0] BACnetObjectIdentifier,
1168  *  messageClass [1] CHOICE {
1169  *      numeric [0] Unsigned,
1170  *      character [1] CharacterString
1171  *      } OPTIONAL,
1172  *  messagePriority [2] ENUMERATED {
1173  *      normal (0),
1174  *      urgent (1)
1175  *      },
1176  *  message [3] CharacterString
1177  * }
1178  * @param tvb
1179  * @param pinfo
1180  * @param tree
1181  * @param offset
1182  * @return modified offset
1183  */
1184 static guint
1185 fUnconfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1186
1187 /**
1188  * TimeSynchronization-Request ::=  SEQUENCE {
1189  *  BACnetDateTime
1190  * }
1191  * @param tvb
1192  * @param tree
1193  * @param offset
1194  * @return modified offset
1195  */
1196 static guint
1197 fTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset);
1198
1199 /**
1200  * UTCTimeSynchronization-Request ::=  SEQUENCE {
1201  *  BACnetDateTime
1202  * }
1203  * @param tvb
1204  * @param tree
1205  * @param offset
1206  * @return modified offset
1207  */
1208 static guint
1209 fUTCTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset);
1210
1211 /**
1212  * Who-Has-Request ::=  SEQUENCE {
1213  *  limits SEQUENCE {
1214  *      deviceInstanceRangeLowLimit [0] Unsigned (0..4194303),
1215  *      deviceInstanceRangeHighLimit [1] Unsigned (0..4194303)
1216  *      } OPTIONAL,
1217  *  object CHOICE {
1218  *      objectIdentifier [2] BACnetObjectIdentifier,
1219  *      objectName [3] CharacterString
1220  *      }
1221  * }
1222  * @param tvb
1223  * @param pinfo
1224  * @param tree
1225  * @param offset
1226  * @return modified offset
1227  */
1228 static guint
1229 fWhoHas (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1230
1231 /**
1232  * Who-Is-Request ::= SEQUENCE {
1233  *      deviceInstanceRangeLowLimit     [0] Unsigned (0..4194303) OPTIONAL, -- must be used as a pair, see 16.9,
1234  *      deviceInstanceRangeHighLimit    [0] Unsigned (0..4194303) OPTIONAL, -- must be used as a pair, see 16.9,
1235  * }
1236  * @param tvb
1237  * @param tree
1238  * @param offset
1239  * @return modified offset
1240  */
1241 static guint
1242 fWhoIsRequest  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1243
1244 /**
1245  * BACnet-Error ::= CHOICE {
1246  *  addListElement          [8] ChangeList-Error,
1247  *  removeListElement       [9] ChangeList-Error,
1248  *  writePropertyMultiple   [16] WritePropertyMultiple-Error,
1249  *  confirmedPrivatTransfer [18] ConfirmedPrivateTransfer-Error,
1250  *  vtClose                 [22] VTClose-Error,
1251  *  readRange               [26] ObjectAccessService-Error
1252  *                      [default] Error
1253  * }
1254  * @param tvb
1255  * @param pinfo
1256  * @param tree
1257  * @param offset
1258  * @param service
1259  * @return modified offset
1260  */
1261 static guint
1262 fBACnetError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint service);
1263
1264 /**
1265  * Dissect a BACnetError in a context tag
1266  *
1267  * @param tvb
1268  * @param pinfo
1269  * @param tree
1270  * @param offset
1271  * @return modified offset
1272  */
1273 static guint fContextTaggedError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1274
1275 /**
1276  * ChangeList-Error ::= SEQUENCE {
1277  *    errorType     [0] Error,
1278  *    firstFailedElementNumber  [1] Unsigned
1279  *    }
1280  * }
1281  * @param tvb
1282  * @param pinfo
1283  * @param tree
1284  * @param offset
1285  * @return modified offset
1286  */
1287 static guint
1288 fChangeListError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1289
1290 /**
1291  * CreateObject-Error ::= SEQUENCE {
1292  *    errorType     [0] Error,
1293  *    firstFailedElementNumber  [1] Unsigned
1294  *    }
1295  * }
1296  * @param tvb
1297  * @param pinfo
1298  * @param tree
1299  * @param offset
1300  * @return modified offset
1301  */
1302 static guint
1303 fCreateObjectError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1304
1305 /**
1306  * ConfirmedPrivateTransfer-Error ::= SEQUENCE {
1307  *    errorType     [0] Error,
1308  *    vendorID      [1] Unsigned,
1309  *    serviceNumber [2] Unsigned,
1310  *    errorParameters   [3] ABSTRACT-SYNTAX.&Type OPTIONAL
1311  *    }
1312  * }
1313  * @param tvb
1314  * @param pinfo
1315  * @param tree
1316  * @param offset
1317  * @return modified offset
1318  */
1319 static guint
1320 fConfirmedPrivateTransferError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1321
1322 /**
1323  * WritePropertyMultiple-Error ::= SEQUENCE {
1324  *    errorType     [0] Error,
1325  *    firstFailedWriteAttempt  [1] Unsigned
1326  *    }
1327  * }
1328  * @param tvb
1329  * @pram pinfo
1330  * @param tree
1331  * @param offset
1332  * @return modified offset
1333  */
1334 static guint
1335 fWritePropertyMultipleError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1336
1337 /**
1338  * VTClose-Error ::= SEQUENCE {
1339  *    errorType     [0] Error,
1340  *    listOfVTSessionIdentifiers  [1] SEQUENCE OF Unsigned8 OPTIONAL
1341  *    }
1342  * }
1343  * @param tvb
1344  * @param pinfo
1345  * @param tree
1346  * @param offset
1347  * @return modified offset
1348  */
1349 static guint
1350 fVTCloseError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1351
1352 /**
1353  * BACnet Application Types chapter 20.2.1
1354  * @param tvb
1355  * @param pinfo
1356  * @param tree
1357  * @param offset
1358  * @param label
1359  * @return modified offset
1360  */
1361 static guint
1362 fApplicationTypes   (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label);
1363
1364 /**
1365  * BACnetActionCommand ::= SEQUENCE {
1366  *  deviceIdentifier    [0] BACnetObjectIdentifier OPTIONAL,
1367  *  objectIdentifier    [1] BACnetObjectIdentifier,
1368  *  propertyIdentifier  [2] BACnetPropertyIdentifier,
1369  *  propertyArrayIndex  [3] Unsigned OPTIONAL, -- used only with array datatype
1370  *  propertyValue       [4] ABSTRACT-SYNTAX.&Type,
1371  *  priority            [5] Unsigned (1..16) OPTIONAL, -- used only when property is commandable
1372  *  postDelay           [6] Unsigned OPTIONAL,
1373  *  quitOnFailure       [7] BOOLEAN,
1374  *  writeSuccessful     [8] BOOLEAN
1375  * }
1376  * @param tvb
1377  * @param pinfo
1378  * @param tree
1379  * @param offset
1380  * @param matching tag number
1381  * @return modified offset
1382  */
1383 static guint
1384 fActionCommand (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tag_match);
1385
1386 /**
1387  * BACnetActionList ::= SEQUENCE {
1388  *  action  [0] SEQUENCE of BACnetActionCommand
1389  * }
1390  * @param tvb
1391  * @param pinfo
1392  * @param tree
1393  * @param offset
1394  * @return modified offset
1395  */
1396 static guint
1397 fActionList (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1398
1399 /** BACnetAddress ::= SEQUENCE {
1400  *  network-number  Unsigned16, -- A value 0 indicates the local network
1401  *  mac-address     OCTET STRING -- A string of length 0 indicates a broadcast
1402  * }
1403  * @param tvb
1404  * @param tree
1405  * @param offset
1406  * @return modified offset
1407  */
1408 static guint
1409 fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset);
1410
1411 /**
1412  * BACnetAddressBinding ::= SEQUENCE {
1413  *      deviceObjectID  BACnetObjectIdentifier
1414  *      deviceAddress   BacnetAddress
1415  * }
1416  * @param tvb
1417  * @param pinfo
1418  * @param tree
1419  * @param offset
1420  * @return modified offset
1421  */
1422 static guint
1423 fAddressBinding (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1424
1425 /**
1426  * BACnetCalendarEntry ::= CHOICE {
1427  *      date        [0] Date,
1428  *      dateRange   [1] BACnetDateRange,
1429  *  weekNDay    [2] BacnetWeekNday
1430  * }
1431  * @param tvb
1432  * @param tree
1433  * @param offset
1434  * @return modified offset
1435  */
1436 static guint
1437 fCalendarEntry (tvbuff_t *tvb, proto_tree *tree, guint offset);
1438
1439 /**
1440  * BACnetClientCOV ::= CHOICE {
1441  *      real-increment  REAL,
1442  *      default-increment   NULL
1443  * }
1444  * @param tvb
1445  * @param tree
1446  * @param offset
1447  * @return modified offset
1448  */
1449 static guint
1450 fClientCOV (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1451
1452
1453 /**
1454  * BACnetDailySchedule ::= SEQUENCE {
1455  *  day-schedule    [0] SENQUENCE OF BACnetTimeValue
1456  * }
1457  * @param tvb
1458  * @param pinfo
1459  * @param tree
1460  * @param offset
1461  * @return modified offset
1462  */
1463 static guint
1464 fDailySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1465
1466 /**
1467  * BACnetWeeklySchedule ::= SEQUENCE {
1468  *  week-schedule    SENQUENCE SIZE (7) OF BACnetDailySchedule
1469  * }
1470  * @param tvb
1471  * @param pinfo
1472  * @param tree
1473  * @param offset
1474  * @return modified offset
1475  */
1476 static guint
1477 fWeeklySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1478
1479 /**
1480  * BACnetDateRange ::= SEQUENCE {
1481  *  StartDate   Date,
1482  *  EndDate     Date
1483  * }
1484  * @param tvb
1485  * @param tree
1486  * @param offset
1487  * @return modified offset
1488  */
1489 static guint
1490 fDateRange (tvbuff_t *tvb, proto_tree *tree, guint offset);
1491
1492 /**
1493  * BACnetDateTime ::= SEQUENCE {
1494  *  date   Date,
1495  *  time   Time
1496  * }
1497  * @param tvb
1498  * @param tree
1499  * @param offset
1500  * @param label
1501  * @return modified offset
1502  */
1503 static guint
1504 fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label);
1505
1506 /**
1507  * BACnetDestination ::= SEQUENCE {
1508  *  validDays   BACnetDaysOfWeek,
1509  *  fromTime    Time,
1510  *  toTime      Time,
1511  *  recipient   BACnetRecipient,
1512  *  processIdentifier   Unsigned32,
1513  *  issueConfirmedNotifications BOOLEAN,
1514  *  transitions BACnetEventTransitionBits
1515  * }
1516  * @param tvb
1517  * @param pinfo
1518  * @param tree
1519  * @param offset
1520  * @return modified offset
1521  */
1522 static guint
1523 fDestination (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1524
1525 /**
1526  * BACnetDeviceObjectPropertyReference ::= SEQUENCE {
1527  *  objectIdentifier    [0] BACnetObjectIdentifier,
1528  *  propertyIdentifier  [1] BACnetPropertyIdentifier,
1529  *  propertyArrayIndex  [2] Unsigend OPTIONAL,
1530  *  deviceIdentifier    [3] BACnetObjectIdentifier OPTIONAL
1531  * }
1532  * @param tvb
1533  * @param pinfo
1534  * @param tree
1535  * @param offset
1536  * @return modified offset
1537  */
1538 static guint
1539 fDeviceObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1540
1541 /**
1542  * BACnetObjectPropertyReference ::= SEQUENCE {
1543  *  objectIdentifier    [0] BACnetObjectIdentifier,
1544  *  propertyIdentifier  [1] BACnetPropertyIdentifier,
1545  *  propertyArrayIndex  [2] Unsigend OPTIONAL,
1546  * }
1547  * @param tvb
1548  * @param pinfo
1549  * @param tree
1550  * @param offset
1551  * @return modified offset
1552  */
1553 static guint
1554 fObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1555
1556 /**
1557  * BACnetDeviceObjectReference ::= SEQUENCE {
1558  *  deviceIdentifier    [0] BACnetObjectIdentifier OPTIONAL,
1559  *  objectIdentifier    [1] BACnetObjectIdentifier
1560  * }
1561  * @param tvb
1562  * @param pinfo
1563  * @param tree
1564  * @param offset
1565  * @return modified offset
1566  */
1567 static guint
1568 fDeviceObjectReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1569
1570 /**
1571  * BACnetEventParameter ::= CHOICE {
1572  *      change-of-bitstring [0] SEQUENCE {
1573  *      time-delay [0] Unsigned,
1574  *      bitmask [1] BIT STRING,
1575  *      list-of-bitstring-values [2] SEQUENCE OF BIT STRING
1576  *      },
1577  *  change-of-state [1] SEQUENCE {
1578  *      time-delay [0] Unsigned,
1579  *      list-of-values [1] SEQUENCE OF BACnetPropertyStates
1580  *      },
1581  *   change-of-value [2] SEQUENCE {
1582  *      time-delay [0] Unsigned,
1583  *      cov-criteria [1] CHOICE {
1584  *              bitmask [0] BIT STRING,
1585  *              referenced-property-increment [1] REAL
1586  *                      }
1587  *              },
1588  *      command-failure [3] SEQUENCE {
1589  *              time-delay [0] Unsigned,
1590  *              feedback-property-reference [1] BACnetDeviceObjectPropertyReference
1591  *              },
1592  *      floating-limit [4] SEQUENCE {
1593  *              time-delay [0] Unsigned,
1594  *              setpoint-reference [1] BACnetDeviceObjectPropertyReference,
1595  *              low-diff-limit [2] REAL,
1596  *              high-diff-limit [3] REAL,
1597  *              deadband [4] REAL
1598  *              },
1599  *      out-of-range [5] SEQUENCE {
1600  *              time-delay [0] Unsigned,
1601  *              low-limit [1] REAL,
1602  *              high-limit [2] REAL,
1603  *              deadband [3] REAL
1604  *              },
1605  *      buffer-ready [7] SEQUENCE {
1606  *              notification-threshold [0] Unsigned,
1607  *              previous-notification-count [1] Unsigned32
1608  *              }
1609  *      change-of-life-safety [8] SEQUENCE {
1610  *              time-delay [0] Unsigned,
1611  *              list-of-life-safety-alarm-values [1] SEQUENCE OF BACnetLifeSafetyState,
1612  *              list-of-alarm-values [2] SEQUENCE OF BACnetLifeSafetyState,
1613  *              mode-property-reference [3] BACnetDeviceObjectPropertyReference
1614  *              }
1615  *      }
1616  * @param tvb
1617  * @param tree
1618  * @param offset
1619  * @return modified offset
1620  */
1621 static guint
1622 fEventParameter (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1623
1624
1625
1626 /**
1627  * BACnetLogRecord ::= SEQUENCE {
1628  *      timestamp [0] BACnetDateTime,
1629  *      logDatum [1] CHOICE {
1630  *              log-status [0] BACnetLogStatus,
1631  *              boolean-value [1] BOOLEAN,
1632  *              real-value [2] REAL,
1633  *              enum-value [3] ENUMERATED, -- Optionally limited to 32 bits
1634  *              unsigned-value [4] Unsigned, -- Optionally limited to 32 bits
1635  *              signed-value [5] INTEGER, -- Optionally limited to 32 bits
1636  *              bitstring-value [6] BIT STRING,-- Optionally limited to 32 bits
1637  *              null-value [7] NULL,
1638  *              failure [8] Error,
1639  *              time-change [9] REAL,
1640  *              any-value [10] ABSTRACT-SYNTAX.&Type -- Optional
1641  *              }
1642  *      statusFlags [2] BACnetStatusFlags OPTIONAL
1643  * }
1644  * @param tvb
1645  * @param pinfo
1646  * @param tree
1647  * @param offset
1648  * @return modified offset
1649  */
1650 static guint
1651 fLogRecord (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1652
1653 /**
1654  * BACnetEventLogRecord ::= SEQUENCE {
1655  *      timestamp [0] BACnetDateTime,
1656  *      logDatum [1] CHOICE {
1657  *              log-status [0] BACnetLogStatus,
1658  *              notification [1] ConfirmedEventNotification-Request,
1659  *              time-change [2] REAL,
1660  *              }
1661  * }
1662  * @param tvb
1663  * @param pinfo
1664  * @param tree
1665  * @param offset
1666  * @return modified offset
1667  */
1668 static guint
1669 fEventLogRecord (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1670
1671 static guint
1672 fLogMultipleRecord (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1673
1674 /**
1675  * BACnetNotificationParameters ::= CHOICE {
1676  *      change-of-bitstring     [0]     SEQUENCE {
1677  *      referenced-bitstring    [0] BIT STRING,
1678  *      status-flags    [1] BACnetStatusFlags
1679  *      },
1680  *  change-of-state [1] SEQUENCE {
1681  *      new-state   [0] BACnetPropertyStatus,
1682  *      status-flags    [1] BACnetStatusFlags
1683  *      },
1684  *  change-of-value [2] SEQUENCE {
1685  *      new-value   [0] CHOICE {
1686  *          changed-bits   [0] BIT STRING,
1687  *          changed-value    [1] REAL
1688  *          },
1689  *      status-flags    [1] BACnetStatusFlags
1690  *      },
1691  *  command-failure [3] SEQUENCE {
1692  *      command-value   [0] ABSTRACT-SYNTAX.&Type, -- depends on ref property
1693  *      status-flags    [1] BACnetStatusFlags
1694  *      feedback-value    [2] ABSTRACT-SYNTAX.&Type -- depends on ref property
1695  *      },
1696  *  floating-limit [4]  SEQUENCE {
1697  *      reference-value   [0] REAL,
1698  *      status-flags    [1] BACnetStatusFlags
1699  *      setpoint-value   [2] REAL,
1700  *      error-limit   [3] REAL
1701  *      },
1702  *  out-of-range [5]    SEQUENCE {
1703  *      exceeding-value   [0] REAL,
1704  *      status-flags    [1] BACnetStatusFlags
1705  *      deadband   [2] REAL,
1706  *      exceeded-limit   [0] REAL
1707  *      },
1708  *  complex-event-type  [6] SEQUENCE OF BACnetPropertyValue,
1709  *  buffer-ready [7]    SEQUENCE {
1710  *      buffer-device   [0] BACnetObjectIdentifier,
1711  *      buffer-object    [1] BACnetObjectIdentifier
1712  *      previous-notification   [2] BACnetDateTime,
1713  *      current-notification   [3] BACnetDateTime
1714  *      },
1715  *  change-of-life-safety [8]   SEQUENCE {
1716  *      new-state   [0] BACnetLifeSafetyState,
1717  *      new-mode    [1] BACnetLifeSafetyState
1718  *      status-flags   [2] BACnetStatusFlags,
1719  *      operation-expected   [3] BACnetLifeSafetyOperation
1720  *      }
1721  * }
1722  * @param tvb
1723  * @param pinfo
1724  * @param tree
1725  * @param offset
1726  * @return modified offset
1727  */
1728 static guint
1729 fNotificationParameters (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1730
1731 /**
1732  * BACnetObjectPropertyReference ::= SEQUENCE {
1733  *      objectIdentifier        [0] BACnetObjectIdentifier,
1734  *      propertyIdentifier      [1] BACnetPropertyIdentifier,
1735  *      propertyArrayIndex      [2] Unsigned OPTIONAL, -- used only with array datatype
1736  * }
1737  * @param tvb
1738  * @param pinfo
1739  * @param tree
1740  * @param offset
1741  * @return modified offset
1742  */
1743 static guint
1744 fBACnetObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1745
1746 #if 0
1747 /**
1748  * BACnetObjectPropertyValue ::= SEQUENCE {
1749  *              objectIdentifier [0] BACnetObjectIdentifier,
1750  *              propertyIdentifier [1] BACnetPropertyIdentifier,
1751  *              propertyArrayIndex [2] Unsigned OPTIONAL, -- used only with array datatype
1752  *                              -- if omitted with an array the entire array is referenced
1753  *              value [3] ABSTRACT-SYNTAX.&Type, --any datatype appropriate for the specified property
1754  *              priority [4] Unsigned (1..16) OPTIONAL
1755  * }
1756  * @param tvb
1757  * @param tree
1758  * @param offset
1759  * @return modified offset
1760  */
1761 static guint
1762 fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset);
1763 #endif
1764
1765 /**
1766  * BACnetPriorityArray ::= SEQUENCE SIZE (16) OF BACnetPriorityValue
1767  * @param tvb
1768  * @param pinfo
1769  * @param tree
1770  * @param offset
1771  * @return modified offset
1772  */
1773 static guint
1774 fPriorityArray (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1775
1776 static guint
1777 fPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset, guint8 list);
1778
1779 /**
1780  * BACnetPropertyReference ::= SEQUENCE {
1781  *      propertyIdentifier      [0] BACnetPropertyIdentifier,
1782  *      propertyArrayIndex      [1] Unsigned OPTIONAL, -- used only with array datatype
1783  * }
1784  * @param tvb
1785  * @param pinfo
1786  * @param tree
1787  * @param offset
1788  * @return modified offset
1789  */
1790 static guint
1791 fBACnetPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 list);
1792
1793 /* static guint
1794 fBACnetObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset); */
1795
1796 static guint
1797 fLOPR (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1798
1799 static guint
1800 fRestartReason (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1801
1802 /**
1803  * BACnetPropertyValue ::= SEQUENCE {
1804  *              PropertyIdentifier [0] BACnetPropertyIdentifier,
1805  *              propertyArrayIndex [1] Unsigned OPTIONAL, -- used only with array datatypes
1806  *                              -- if omitted with an array the entire array is referenced
1807  *              value [2] ABSTRACT-SYNTAX.&Type, -- any datatype appropriate for the specified property
1808  *              priority [3] Unsigned (1..16) OPTIONAL -- used only when property is commandable
1809  * }
1810  * @param tvb
1811  * @param pinfo
1812  * @param tree
1813  * @param offset
1814  * @return modified offset
1815  */
1816 static guint
1817 fBACnetPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1818
1819 static guint
1820 fPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset);
1821
1822 /**
1823  * BACnet Application PDUs chapter 21
1824  * BACnetRecipient::= CHOICE {
1825  *      device  [0] BACnetObjectIdentifier
1826  *      address [1] BACnetAddress
1827  * }
1828  * @param tvb
1829  * @param pinfo
1830  * @param tree
1831  * @param offset
1832  * @return modified offset
1833  */
1834 static guint
1835 fRecipient (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1836
1837 /**
1838  * BACnet Application PDUs chapter 21
1839  * BACnetRecipientProcess::= SEQUENCE {
1840  *      recipient       [0] BACnetRecipient
1841  *      processID       [1] Unsigned32
1842  * }
1843  * @param tvb
1844  * @param pinfo
1845  * @param tree
1846  * @param offset
1847  * @return modified offset
1848  */
1849 static guint
1850 fRecipientProcess (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1851
1852 static guint
1853 fCOVSubscription (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1854
1855 #if 0
1856 /**
1857  * BACnetSessionKey ::= SEQUENCE {
1858  *      sessionKey      OCTET STRING (SIZE(8)), -- 56 bits for key, 8 bits for checksum
1859  *      peerAddress     BACnetAddress
1860  * }
1861  * @param tvb
1862  * @param tree
1863  * @param offset
1864  * @return modified offset
1865  * @todo check if checksum is displayed correctly
1866  */
1867 static guint
1868 fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset);
1869 #endif
1870
1871 /**
1872  * BACnetSpecialEvent ::= SEQUENCE {
1873  *      period          CHOICE {
1874  *              calendarEntry           [0] BACnetCalendarEntry,
1875  *              calendarRefernce        [1] BACnetObjectIdentifier
1876  *              },
1877  *              listOfTimeValues        [2] SEQUENCE OF BACnetTimeValue,
1878  *              eventPriority           [3] Unsigned (1..16)
1879  * }
1880  * @param tvb
1881  * @param pinfo
1882  * @param tree
1883  * @param offset
1884  * @return modified offset
1885  */
1886 static guint
1887 fSpecialEvent (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1888
1889 /**
1890  * BACnetTimeStamp ::= CHOICE {
1891  *      time                    [0] Time,
1892  *      sequenceNumber  [1] Unsigned (0..65535),
1893  *      dateTime                [2] BACnetDateTime
1894  * }
1895  * @param tvb
1896  * @param tree
1897  * @param offset
1898  * @param label
1899  * @return modified offset
1900  */
1901 static guint
1902 fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label);
1903
1904 static guint
1905 fEventTimeStamps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1906
1907 /**
1908  * BACnetTimeValue ::= SEQUENCE {
1909  *      time    Time,
1910  *      value   ABSTRACT-SYNTAX.&Type -- any primitive datatype, complex types cannot be decoded
1911  * }
1912  * @param tvb
1913  * @param pinfo
1914  * @param tree
1915  * @param offset
1916  * @return modified offset
1917  */
1918 static guint
1919 fTimeValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1920
1921 #if 0
1922 /**
1923  * BACnetVTSession ::= SEQUENCE {
1924  *      local-vtSessionID       Unsigned8,
1925  *      remote-vtSessionID      Unsigned8,
1926  *      remote-vtAddress        BACnetAddress
1927  * }
1928  * @param tvb
1929  * @param tree
1930  * @param offset
1931  * @return modified offset
1932  */
1933 static guint
1934 fVTSession (tvbuff_t *tvb, proto_tree *tree, guint offset);
1935 #endif
1936
1937 /**
1938  * BACnetWeekNDay ::= OCTET STRING (SIZE (3))
1939  * -- first octet month (1..12) January = 1, X'FF' = any month
1940  * -- second octet weekOfMonth where: 1 = days numbered 1-7
1941  * -- 2 = days numbered 8-14
1942  * -- 3 = days numbered 15-21
1943  * -- 4 = days numbered 22-28
1944  * -- 5 = days numbered 29-31
1945  * -- 6 = last 7 days of this month
1946  * -- X'FF' = any week of this month
1947  * -- third octet dayOfWeek (1..7) where 1 = Monday
1948  * -- 7 = Sunday
1949  * -- X'FF' = any day of week
1950  * @param tvb
1951  * @param tree
1952  * @param offset
1953  * @return modified offset
1954  */
1955 static guint
1956 fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset);
1957
1958 /**
1959  * ReadAccessResult ::= SEQUENCE {
1960  *      objectIdentifier        [0] BACnetObjectIdentifier,
1961  *      listOfResults   [1] SEQUENCE OF SEQUENCE {
1962  *              propertyIdentifier      [2] BACnetPropertyIdentifier,
1963  *              propertyArrayIndex      [3] Unsigned OPTIONAL, -- used only with array datatype if omitted with an array the entire array is referenced
1964  *              readResult      CHOICE {
1965  *                      propertyValue   [4] ABSTRACT-SYNTAX.&Type,
1966  *                      propertyAccessError     [5] Error
1967  *              }
1968  *  } OPTIONAL
1969  * }
1970  * @param tvb
1971  * @param pinfo
1972  * @param tree
1973  * @param offset
1974  * @return modified offset
1975  */
1976 static guint
1977 fReadAccessResult (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
1978
1979 /**
1980  * ReadAccessSpecification ::= SEQUENCE {
1981  *      objectIdentifier        [0] BACnetObjectIdentifier,
1982  *      listOfPropertyReferences        [1] SEQUENCE OF BACnetPropertyReference
1983  * }
1984  * @param tvb
1985  * @param pinfo
1986  * @param tree
1987  * @param offset
1988  * @return modified offset
1989  */
1990 static guint
1991 fReadAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset);
1992
1993 /**
1994  * WriteAccessSpecification ::= SEQUENCE {
1995  *      objectIdentifier        [0] BACnetObjectIdentifier,
1996  *      listOfProperty  [1] SEQUENCE OF BACnetPropertyValue
1997  * }
1998  * @param tvb
1999  * @param pinfo
2000  * @param tree
2001  * @param offset
2002  * @return modified offset
2003  */
2004 static guint
2005 fWriteAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset);
2006
2007
2008 /********************************************************* Helper functions *******************************************/
2009
2010 /**
2011  * extracts the tag number from the tag header.
2012  * @param tvb "TestyVirtualBuffer"
2013  * @param offset in actual tvb
2014  * @return Tag Number corresponding to BACnet 20.2.1.2 Tag Number
2015  */
2016 static guint
2017 fTagNo (tvbuff_t *tvb, guint offset);
2018
2019 /**
2020  * splits Tag Header coresponding to 20.2.1 General Rules For BACnet Tags
2021  * @param tvb = "TestyVirtualBuffer"
2022  * @param offset = offset in actual tvb
2023  * @return tag_no BACnet 20.2.1.2 Tag Number
2024  * @return class_tag BACnet 20.2.1.1 Class
2025  * @return lvt BACnet 20.2.1.3 Length/Value/Type
2026  * @return offs = length of this header
2027  */
2028
2029 static guint
2030 fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* class_tag, guint32 *lvt);
2031
2032
2033 /**
2034  * adds processID with max 32Bit unsigned Integer Value to tree
2035  * @param tvb
2036  * @param tree
2037  * @param offset
2038  * @return modified offset
2039  */
2040 static guint
2041 fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset);
2042
2043 /**
2044  * adds timeSpan with max 32Bit unsigned Integer Value to tree
2045  * @param tvb
2046  * @param tree
2047  * @param offset
2048  * @return modified offset
2049  */
2050 static guint
2051 fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label);
2052
2053 /**
2054  * BACnet Application PDUs chapter 21
2055  * BACnetPropertyIdentifier::= ENUMERATED {
2056  *       @see bacapp_property_identifier
2057  * }
2058  * @param tvb
2059  * @param pinfo
2060  * @param tree
2061  * @param offset
2062  * @param tt returnvalue of this item
2063  * @return modified offset
2064  */
2065 static guint
2066 fPropertyIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
2067
2068 /**
2069  * BACnet Application PDUs chapter 21
2070  * BACnetPropertyArrayIndex::= ENUMERATED {
2071  *       @see bacapp_property_array_index
2072  * }
2073  * @param tvb
2074  * @param tree
2075  * @param offset
2076  * @param tt returnvalue of this item
2077  * @return modified offset
2078  */
2079 static guint
2080 fPropertyArrayIndex (tvbuff_t *tvb, proto_tree *tree, guint offset);
2081
2082 /**
2083  * listOfEventSummaries ::= SEQUENCE OF SEQUENCE {
2084  *      objectIdentifier        [0] BACnetObjectIdentifier,
2085  *  eventState  [1] BACnetEventState,
2086  *  acknowledgedTransitions [2] BACnetEventTransitionBits,
2087  *  eventTimeStamps [3] SEQURNCE SIZE (3) OF BACnetTimeStamps,
2088  *  notifyType  [4] BACnetNotifyType,
2089  *  eventEnable [5] BACnetEventTransitionBits,
2090  *  eventPriorities [6] SEQUENCE SIZE (3) OF Unsigned
2091  * }
2092  * @param tvb
2093  * @param pinfo
2094  * @param tree
2095  * @param offset
2096  * @return modified offset
2097  */
2098 static guint
2099 flistOfEventSummaries (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
2100
2101 /**
2102  * SelectionCriteria ::= SEQUENCE {
2103  *      propertyIdentifier      [0] BACnetPropertyIdentifier,
2104  *      propertyArrayIndex      [1] Unsigned OPTIONAL, -- used only with array datatype
2105  *  relationSpecifier   [2] ENUMERATED { bacapp_relationSpecifier },
2106  *  comparisonValue     [3] ABSTRACT-SYNTAX.&Type
2107  * }
2108  * @param tvb
2109  * @param pinfo
2110  * @param tree
2111  * @param offset
2112  * @return modified offset
2113  */
2114 static guint
2115 fSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
2116
2117 /**
2118  * objectSelectionCriteria ::= SEQUENCE {
2119  *      selectionLogic  [0] ENUMERATED { bacapp_selectionLogic },
2120  *      listOfSelectionCriteria [1] SelectionCriteria
2121  * }
2122  * @param tvb
2123  * @param pinfo
2124  * @param tree
2125  * @param offset
2126  * @return modified offset
2127  */
2128 static guint
2129 fObjectSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset);
2130
2131 /**
2132  * BACnet-Error ::= SEQUENCE {
2133  *    error-class ENUMERATED {},
2134  *    error-code  ENUMERATED {}
2135  *    }
2136  * }
2137  * @param tvb
2138  * @param pinfo
2139  * @param tree
2140  * @param offset
2141  * @return modified offset
2142  */
2143 static guint
2144 fError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
2145
2146 /**
2147  * Generic handler for context tagged values.  Mostly for handling
2148  * vendor-defined properties and services.
2149  * @param tvb
2150  * @param tree
2151  * @param offset
2152  * @return modified offset
2153  * @todo beautify this ugly construct
2154  */
2155 static guint
2156 fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label);
2157
2158 /**
2159  * realizes some ABSTRACT-SYNTAX.&Type
2160  * @param tvb
2161  * @param pinfo
2162  * @param tree
2163  * @param offset
2164  * @return modified offset
2165  * @todo beautify this ugly construct
2166  */
2167 static guint
2168 fAbstractSyntaxNType (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset);
2169
2170
2171 static guint
2172 fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
2173         const value_string *src);
2174
2175 /**
2176  * register_bacapp
2177  */
2178 void
2179 proto_register_bacapp(void);
2180
2181 /**
2182  * proto_reg_handoff_bacapp
2183  */
2184 void
2185 proto_reg_handoff_bacapp(void);
2186
2187 /**
2188  * converts XXX coded strings to UTF-8
2189  * else 'in' is copied to 'out'
2190  * @param in  -- pointer to string
2191  * @param inbytesleft
2192  * @param out -- pointer to string
2193  * @param outbytesleft
2194  * @param fromcoding
2195  * @return count of modified characters of returned string, -1 for errors
2196  */
2197 static guint32
2198 fConvertXXXtoUTF8(gchar *in, gsize *inbytesleft, gchar *out, gsize *outbytesleft, const gchar *fromcoding);
2199
2200 static void
2201 uni_to_string(char * data, gsize str_length, char *dest_buf);
2202
2203 /* <<<< formerly bacapp.h */
2204
2205 /* some hashes for segmented messages */
2206 static GHashTable *msg_fragment_table = NULL;
2207 static GHashTable *msg_reassembled_table = NULL;
2208
2209 /* some necessary forward function prototypes */
2210 static guint
2211 fApplicationTypesEnumerated (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset,
2212         const gchar *label, const value_string *vs);
2213
2214 static const char *bacapp_unknown_service_str = "unknown service";
2215 static const char *ASHRAE_Reserved_Fmt = "(%d) Reserved for Use by ASHRAE";
2216 static const char *Vendor_Proprietary_Fmt = "(%d) Vendor Proprietary Value";
2217
2218 static const value_string
2219 BACnetTypeName[] = {
2220         {0, "Confirmed-REQ"},
2221         {1, "Unconfirmed-REQ"},
2222         {2, "Simple-ACK"},
2223         {3, "Complex-ACK"},
2224         {4, "Segment-ACK"},
2225         {5, "Error"},
2226         {6, "Reject"},
2227         {7, "Abort"},
2228         {0, NULL }
2229 };
2230
2231 static const true_false_string segments_follow = {
2232         "Segmented Request",
2233         "Unsegmented Request"
2234 };
2235
2236 static const true_false_string more_follow = {
2237         "More Segments Follow",
2238         "No More Segments Follow"
2239 };
2240
2241 static const true_false_string segmented_accept = {
2242         "Segmented Response accepted",
2243         "Segmented Response not accepted"
2244 };
2245
2246 static const true_false_string
2247 BACnetTagClass = {
2248         "Context Specific Tag",
2249         "Application Tag"
2250 };
2251
2252 static const value_string
2253 BACnetMaxSegmentsAccepted [] = {
2254         {0,"Unspecified"},
2255         {1,"2 segments"},
2256         {2,"4 segments"},
2257         {3,"8 segments"},
2258         {4,"16 segments"},
2259         {5,"32 segments"},
2260         {6,"64 segments"},
2261         {7,"Greater than 64 segments"},
2262         {0,NULL }
2263 };
2264
2265 static const value_string
2266 BACnetMaxAPDULengthAccepted [] = {
2267         {0,"Up to MinimumMessageSize (50 octets)"},
2268         {1,"Up to 128 octets"},
2269         {2,"Up to 206 octets (fits in a LonTalk frame)"},
2270         {3,"Up to 480 octets (fits in an ARCNET frame)"},
2271         {4,"Up to 1024 octets"},
2272         {5,"Up to 1476 octets (fits in an ISO 8802-3 frame)"},
2273         {6,"reserved by ASHRAE"},
2274         {7,"reserved by ASHRAE"},
2275         {8,"reserved by ASHRAE"},
2276         {9,"reserved by ASHRAE"},
2277         {10,"reserved by ASHRAE"},
2278         {11,"reserved by ASHRAE"},
2279         {12,"reserved by ASHRAE"},
2280         {13,"reserved by ASHRAE"},
2281         {14,"reserved by ASHRAE"},
2282         {15,"reserved by ASHRAE"},
2283         {0,NULL}
2284 };
2285
2286 static const value_string
2287 BACnetRejectReason [] = {
2288         {0,"other"},
2289         {1,"buffer-overflow"},
2290         {2,"inconsistent-parameters"},
2291         {3,"invalid-parameter-data-type"},
2292         {4,"invalid-tag"},
2293         {5,"missing-required-parameter"},
2294         {6,"parameter-out-of-range"},
2295         {7,"too-many-arguments"},
2296         {8,"undefined-enumeration"},
2297         {9,"unrecognized-service"},
2298         {0,NULL}
2299 };
2300
2301 static const value_string
2302 BACnetRestartReason [] = {
2303         {0,"unknown"},
2304         {1,"coldstart"},
2305         {2,"warmstart"},
2306         {3,"detected-power-lost"},
2307         {4,"detected-powered-off"},
2308         {5,"hardware-watchdog"},
2309         {6,"software-watchdog"},
2310         {7,"suspended"},
2311         {0,NULL}
2312 };
2313
2314 static const value_string
2315 BACnetApplicationTagNumber [] = {
2316         {0,"Null"},
2317         {1,"Boolean"},
2318         {2,"Unsigned Integer"},
2319         {3,"Signed Integer (2's complement notation)"},
2320         {4,"Real (ANSI/IEE-754 floating point)"},
2321         {5,"Double (ANSI/IEE-754 double precision floating point)"},
2322         {6,"Octet String"},
2323         {7,"Character String"},
2324         {8,"Bit String"},
2325         {9,"Enumerated"},
2326         {10,"Date"},
2327         {11,"Time"},
2328         {12,"BACnetObjectIdentifier"},
2329         {13,"reserved by ASHRAE"},
2330         {14,"reserved by ASHRAE"},
2331         {15,"reserved by ASHRAE"},
2332         {0,NULL}
2333 };
2334
2335 static const value_string
2336 BACnetAction [] = {
2337         {0,"direct"},
2338         {1,"reverse"},
2339         {0,NULL}
2340 };
2341
2342 static const value_string
2343 BACnetFileAccessMethod [] = {
2344         {0,"record-access"},
2345         {1,"stream-access"},
2346         {0,NULL}
2347 };
2348
2349 /* For some reason, BACnet defines the choice parameter
2350    in the file read and write services backwards from the
2351    BACnetFileAccessMethod enumeration.
2352 */
2353 static const value_string
2354 BACnetFileAccessOption [] = {
2355         {0,"stream access"},
2356         {1,"record access"},
2357         {0,NULL}
2358 };
2359
2360 static const value_string
2361 BACnetFileStartOption [] = {
2362         {0, "File Start Position: "},
2363         {1, "File Start Record: "},
2364         {0, NULL}
2365 };
2366
2367 static const value_string
2368 BACnetFileRequestCount [] = {
2369         {0, "Requested Octet Count: "},
2370         {1, "Requested Record Count: "},
2371         {0, NULL}
2372 };
2373
2374 static const value_string
2375 BACnetFileWriteInfo [] = {
2376         {0, "File Data: "},
2377         {1, "Record Count: "},
2378         {0, NULL}
2379 };
2380
2381 static const value_string
2382 BACnetAbortReason [] = {
2383         {0,"other"},
2384         {1,"buffer-overflow"},
2385         {2,"invalid-apdu-in-this-state"},
2386         {3,"preempted-by-higher-priority-task"},
2387         {4,"segmentation-not-supported"},
2388         {0,NULL}
2389 };
2390
2391 static const value_string
2392 BACnetLifeSafetyMode [] = {
2393         {0,"off"},
2394         {1,"on"},
2395         {2,"test"},
2396         {3,"manned"},
2397         {4,"unmanned"},
2398         {5,"armed"},
2399         {6,"disarmed"},
2400         {7,"prearmed"},
2401         {8,"slow"},
2402         {9,"fast"},
2403         {10,"disconnected"},
2404         {11,"enabled"},
2405         {12,"disabled"},
2406         {13,"atomic-release-disabled"},
2407         {14,"default"},
2408         {0,NULL}
2409 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
2410    Enumerated values 256-65535 may be used by others subject to
2411    procedures and constraints described in Clause 23. */
2412 };
2413
2414 static const value_string
2415 BACnetLifeSafetyOperation [] = {
2416         {0,"none"},
2417         {1,"silence"},
2418         {2,"silence-audible"},
2419         {3,"silence-visual"},
2420         {4,"reset"},
2421         {5,"reset-alarm"},
2422         {6,"reset-fault"},
2423         {7,"unsilence"},
2424         {8,"unsilence-audible"},
2425         {9,"unsilence-visual"},
2426         {0,NULL}
2427 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
2428    Enumerated values 64-65535 may be used by others subject to
2429    procedures and constraints described in Clause 23. */
2430 };
2431
2432 static const value_string
2433 BACnetLimitEnable [] = {
2434         {0,"lowLimitEnable"},
2435         {1,"highLimitEnable"},
2436         {0,NULL}
2437 };
2438
2439 static const value_string
2440 BACnetLifeSafetyState [] = {
2441         {0,"quiet"},
2442         {1,"pre-alarm"},
2443         {2,"alarm"},
2444         {3,"fault"},
2445         {4,"fault-pre-alarm"},
2446         {5,"fault-alarm"},
2447         {6,"not-ready"},
2448         {7,"active"},
2449         {8,"tamper"},
2450         {9,"test-alarm"},
2451         {10,"test-active"},
2452         {11,"test-fault"},
2453         {12,"test-fault-alarm"},
2454         {13,"holdup"},
2455         {14,"duress"},
2456         {15,"tamper-alarm"},
2457         {16,"abnormal"},
2458         {17,"emergency-power"},
2459         {18,"delayed"},
2460         {19,"blocked"},
2461         {20,"local-alarm"},
2462         {21,"general-alarm"},
2463         {22,"supervisory"},
2464         {23,"test-supervisory"},
2465         {0,NULL}
2466 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
2467    Enumerated values 256-65535 may be used by others subject to
2468    procedures and constraints described in Clause 23. */
2469 };
2470
2471 static const value_string
2472 BACnetConfirmedServiceChoice [] = {
2473         {0,"acknowledgeAlarm"},
2474         {1,"confirmedCOVNotification"},
2475         {2,"confirmedEventNotification"},
2476         {3,"getAlarmSummary"},
2477         {4,"getEnrollmentSummary"},
2478         {5,"subscribeCOV"},
2479         {6,"atomicReadFile"},
2480         {7,"atomicWriteFile"},
2481         {8,"addListElement"},
2482         {9,"removeListElement"},
2483         {10,"createObject"},
2484         {11,"deleteObject"},
2485         {12,"readProperty"},
2486         {13,"readPropertyConditional"},
2487         {14,"readPropertyMultiple"},
2488         {15,"writeProperty"},
2489         {16,"writePropertyMultiple"},
2490         {17,"deviceCommunicationControl"},
2491         {18,"confirmedPrivateTransfer"},
2492         {19,"confirmedTextMessage"},
2493         {20,"reinitializeDevice"},
2494         {21,"vtOpen"},
2495         {22,"vtClose"},
2496         {23,"vtData"},
2497         {24,"authenticate"},
2498         {25,"requestKey"},
2499         {26,"readRange"},
2500         {27,"lifeSafetyOperation"},
2501         {28,"subscribeCOVProperty"},
2502         {29,"getEventInformation"},
2503         {30,"reserved by ASHRAE"},
2504         {0, NULL}
2505 };
2506
2507 static const value_string
2508 BACnetReliability [] = {
2509         {0,"no-fault-detected"},
2510         {1,"no-sensor"},
2511         {2,"over-range"},
2512         {3,"under-range"},
2513         {4,"open-loop"},
2514         {5,"shorted-loop"},
2515         {6,"no-output"},
2516         {7,"unreliable-other"},
2517         {8,"process-error"},
2518         {9,"multi-state-fault"},
2519         {10,"configuration-error"},
2520         /* enumeration value 11 is reserved for a future addendum */
2521         {12,"communication-failure"},
2522         {13,"member-fault"},
2523         {0,NULL}
2524 };
2525
2526 static const value_string
2527 BACnetUnconfirmedServiceChoice [] = {
2528         {0,"i-Am"},
2529         {1,"i-Have"},
2530         {2,"unconfirmedCOVNotification"},
2531         {3,"unconfirmedEventNotification"},
2532         {4,"unconfirmedPrivateTransfer"},
2533         {5,"unconfirmedTextMessage"},
2534         {6,"timeSynchronization"},
2535         {7,"who-Has"},
2536         {8,"who-Is"},
2537         {9,"utcTimeSynchonization"},
2538         {0,NULL}
2539 };
2540
2541 static const value_string
2542 BACnetUnconfirmedServiceRequest [] = {
2543         {0,"i-Am-Request"},
2544         {1,"i-Have-Request"},
2545         {2,"unconfirmedCOVNotification-Request"},
2546         {3,"unconfirmedEventNotification-Request"},
2547         {4,"unconfirmedPrivateTransfer-Request"},
2548         {5,"unconfirmedTextMessage-Request"},
2549         {6,"timeSynchronization-Request"},
2550         {7,"who-Has-Request"},
2551         {8,"who-Is-Request"},
2552         {9,"utcTimeSynchonization-Request"},
2553         {0,NULL}
2554 };
2555
2556 static const value_string
2557 BACnetObjectType [] = {
2558         {0,"analog-input"},
2559         {1,"analog-output"},
2560         {2,"analog-value"},
2561         {3,"binary-input"},
2562         {4,"binary-output"},
2563         {5,"binary-value"},
2564         {6,"calendar"},
2565         {7,"command"},
2566         {8,"device"},
2567         {9,"event-enrollment"},
2568         {10,"file"},
2569         {11,"group"},
2570         {12,"loop"},
2571         {13,"multi-state-input"},
2572         {14,"multi-state-output"},
2573         {15,"notification-class"},
2574         {16,"program"},
2575         {17,"schedule"},
2576         {18,"averaging"},
2577         {19,"multi-state-value"},
2578         {20,"trend-log"},
2579         {21,"life-safety-point"},
2580         {22,"life-safety-zone"},
2581         {23,"accumulator"},
2582         {24,"pulse-converter"},
2583         {25,"event-log"},
2584         {26,"global-group"},
2585         {27,"trend-log-multiple"},
2586         {28,"load-control"},
2587         {29,"structured-view"},
2588         {30,"access-door"},             /* 30-37 added with addanda 135-2008j */
2589         /* value 31 is unassigned */
2590         {32,"access-credential"},
2591         {33,"access-point"},
2592         {34,"access-rights"},
2593         {35,"access-user"},
2594         {36,"access-zone"},
2595         {37,"credential-data-input"},
2596         {38,"network-security"},
2597         {39,"bitstring-value"},         /* 39-50 added with addenda 135-2008w */
2598         {40,"characterstring-value"},
2599         {41,"date-pattern-value"},
2600         {42,"date-value"},
2601         {43,"datetime-pattern-value"},
2602         {44,"datetime-value"},
2603         {45,"integer-value"},
2604         {46,"large-analog-value"},
2605         {47,"octetstring-value"},
2606         {48,"positive-integer-value"},
2607         {49,"time-pattern-value"},
2608         {50,"time-value"},
2609         {0, NULL}
2610 /* Enumerated values 0-127 are reserved for definition by ASHRAE.
2611    Enumerated values 128-1023 may be used by others subject to
2612    the procedures and constraints described in Clause 23. */
2613 };
2614
2615 static const value_string
2616 BACnetEngineeringUnits [] = {
2617         {0,"Sq Meters"},
2618         {1,"Sq Feet"},
2619         {2,"Milliamperes"},
2620         {3,"Amperes"},
2621         {4,"Ohms"},
2622         {5,"Volts"},
2623         {6,"Kilovolts"},
2624         {7,"Megavolts"},
2625         {8,"Volt Amperes"},
2626         {9,"Kilovolt Amperes"},
2627         {10,"Megavolt Amperes"},
2628         {11,"Volt Amperes Reactive"},
2629         {12,"Kilovolt Amperes Reactive"},
2630         {13,"Megavolt Amperes Reactive"},
2631         {14,"Degrees Phase"},
2632         {15,"Power Factor"},
2633         {16,"Joules"},
2634         {17,"Kilojoules"},
2635         {18,"Watt Hours"},
2636         {19,"Kilowatt Hours"},
2637         {20,"BTUs"},
2638         {21,"Therms"},
2639         {22,"Ton Hours"},
2640         {23,"Joules Per Kg Dry Air"},
2641         {24,"BTUs Per Pound Dry Air"},
2642         {25,"Cycles Per Hour"},
2643         {26,"Cycles Per Minute"},
2644         {27,"Hertz"},
2645         {28,"Grams Of Water Per Kilogram Dry Air"},
2646         {29,"Relative Humidity"},
2647         {30,"Millimeters"},
2648         {31,"Meters"},
2649         {32,"Inches"},
2650         {33,"Feed"},
2651         {34,"Watts Per Sq Foot"},
2652         {35,"Watts Per Sq meter"},
2653         {36,"Lumens"},
2654         {37,"Lux"},
2655         {38,"Foot Candles"},
2656         {39,"Kilograms"},
2657         {40,"Pounds Mass"},
2658         {41,"Tons"},
2659         {42,"Kgs per Second"},
2660         {43,"Kgs Per Minute"},
2661         {44,"Kgs Per Hour"},
2662         {45,"Pounds Mass Per Minute"},
2663         {46,"Pounds Mass Per Hour"},
2664         {47,"Watt"},
2665         {48,"Kilowatts"},
2666         {49,"Megawatts"},
2667         {50,"BTUs Per Hour"},
2668         {51,"Horsepower"},
2669         {52,"Tons Refrigeration"},
2670         {53,"Pascals"},
2671         {54,"Kilopascals"},
2672         {55,"Bars"},
2673         {56,"Pounds Force Per Square Inch"},
2674         {57,"Centimeters Of Water"},
2675         {58,"Inches Of Water"},
2676         {59,"Millimeters Of Mercury"},
2677         {60,"Centimeters Of Mercury"},
2678         {61,"Inches Of Mercury"},
2679         {62,"Degrees Celsius"},
2680         {63,"Degrees Kelvin"},
2681         {64,"Degrees Fahrenheit"},
2682         {65,"Degree Days Celsius"},
2683         {66,"Degree Days Fahrenheit"},
2684         {67,"Years"},
2685         {68,"Months"},
2686         {69,"Weeks"},
2687         {70,"Days"},
2688         {71,"Hours"},
2689         {72,"Minutes"},
2690         {73,"Seconds"},
2691         {74,"Meters Per Second"},
2692         {75,"Kilometers Per Hour"},
2693         {76,"Feed Per Second"},
2694         {77,"Feet Per Minute"},
2695         {78,"Miles Per Hour"},
2696         {79,"Cubic Feet"},
2697         {80,"Cubic Meters"},
2698         {81,"Imperial Gallons"},
2699         {82,"Liters"},
2700         {83,"US Gallons"},
2701         {84,"Cubic Feet Per Minute"},
2702         {85,"Cubic Meters Per Second"},
2703         {86,"Imperial Gallons Per Minute"},
2704         {87,"Liters Per Second"},
2705         {88,"Liters Per Minute"},
2706         {89,"US Gallons Per Minute"},
2707         {90,"Degrees Angular"},
2708         {91,"Degrees Celsius Per Hour"},
2709         {92,"Degrees Celsius Per Minute"},
2710         {93,"Degrees Fahrenheit Per Hour"},
2711         {94,"Degrees Fahrenheit Per Minute"},
2712         {95,"No Units"},
2713         {96,"Parts Per Million"},
2714         {97,"Parts Per Billion"},
2715         {98,"Percent"},
2716         {99,"Pecent Per Second"},
2717         {100,"Per Minute"},
2718         {101,"Per Second"},
2719         {102,"Psi Per Degree Fahrenheit"},
2720         {103,"Radians"},
2721         {104,"Revolutions Per Min"},
2722         {105,"Currency1"},
2723         {106,"Currency2"},
2724         {107,"Currency3"},
2725         {108,"Currency4"},
2726         {109,"Currency5"},
2727         {110,"Currency6"},
2728         {111,"Currency7"},
2729         {112,"Currency8"},
2730         {113,"Currency9"},
2731         {114,"Currency10"},
2732         {115,"Sq Inches"},
2733         {116,"Sq Centimeters"},
2734         {117,"BTUs Per Pound"},
2735         {118,"Centimeters"},
2736         {119,"Pounds Mass Per Second"},
2737         {120,"Delta Degrees Fahrenheit"},
2738         {121,"Delta Degrees Kelvin"},
2739         {122,"Kilohms"},
2740         {123,"Megohms"},
2741         {124,"Millivolts"},
2742         {125,"Kilojoules Per Kg"},
2743         {126,"Megajoules"},
2744         {127,"Joules Per Degree Kelvin"},
2745         {128,"Joules Per Kg Degree Kelvin"},
2746         {129,"Kilohertz"},
2747         {130,"Megahertz"},
2748         {131,"Per Hour"},
2749         {132,"Milliwatts"},
2750         {133,"Hectopascals"},
2751         {134,"Millibars"},
2752         {135,"Cubic Meters Per Hour"},
2753         {136,"Liters Per Hour"},
2754         {137,"KWatt Hours Per Square Meter"},
2755         {138,"KWatt Hours Per Square Foot"},
2756         {139,"Megajoules Per Square Meter"},
2757         {140,"Megajoules Per Square Foot"},
2758         {141,"Watts Per Sq Meter Degree Kelvin"},
2759         {142,"Cubic Feet Per Second"},
2760         {143,"Percent Obstruction Per Foot"},
2761         {144,"Percent Obstruction Per Meter"},
2762         {145,"milliohms"},
2763         {146,"megawatt-hours"},
2764         {147,"kilo-btus"},
2765         {148,"mega-btus"},
2766         {149,"kilojoules-per-kilogram-dry-air"},
2767         {150,"megajoules-per-kilogram-dry-air"},
2768         {151,"kilojoules-per-degree-Kelvin"},
2769         {152,"megajoules-per-degree-Kelvin"},
2770         {153,"newton"},
2771         {154,"grams-per-second"},
2772         {155,"grams-per-minute"},
2773         {156,"tons-per-hour"},
2774         {157,"kilo-btus-per-hour"},
2775         {158,"hundredths-seconds"},
2776         {159,"milliseconds"},
2777         {160,"newton-meters"},
2778         {161,"millimeters-per-second"},
2779         {162,"millimeters-per-minute"},
2780         {163,"meters-per-minute"},
2781         {164,"meters-per-hour"},
2782         {165,"cubic-meters-per-minute"},
2783         {166,"meters-per-second-per-second"},
2784         {167,"amperes-per-meter"},
2785         {168,"amperes-per-square-meter"},
2786         {169,"ampere-square-meters"},
2787         {170,"farads"},
2788         {171,"henrys"},
2789         {172,"ohm-meters"},
2790         {173,"siemens"},
2791         {174,"siemens-per-meter"},
2792         {175,"teslas"},
2793         {176,"volts-per-degree-Kelvin"},
2794         {177,"volts-per-meter"},
2795         {178,"webers"},
2796         {179,"candelas"},
2797         {180,"candelas-per-square-meter"},
2798         {181,"degrees-Kelvin-per-hour"},
2799         {182,"degrees-Kelvin-per-minute"},
2800         {183,"joule-seconds"},
2801         {184,"radians-per-second"},
2802         {185,"square-meters-per-Newton"},
2803         {186,"kilograms-per-cubic-meter"},
2804         {187,"newton-seconds"},
2805         {188,"newtons-per-meter"},
2806         {189,"watts-per-meter-per-degree-Kelvin"},
2807         {190,"micro-siemens"},
2808         {191,"cubic-feet-per-hour"},
2809         {192,"us-gallons-per-hour"},
2810         {193,"kilometers"},
2811         {194,"micrometers"},
2812         {195,"grams"},
2813         {196,"milligrams"},
2814         {197,"milliliters"},
2815         {198,"milliliters-per-second"},
2816         {199,"decibels"},
2817         {200,"decibels-millivolt"},
2818         {201,"decibels-volt"},
2819         {202,"millisiemens"},
2820         {203,"watt-hours-reactive"},
2821         {204,"kilowatt-hours-reactive"},
2822         {205,"megawatt-hours-reactive"},
2823         {206,"millimeters-of-water"},
2824         {207,"per-mille"},
2825         {208,"grams-per-gram"},
2826         {209,"kilograms-per-kilogram"},
2827         {210,"grams-per-kilogram"},
2828         {211,"milligrams-per-gram"},
2829         {212,"milligrams-per-kilogram"},
2830         {213,"grams-per-milliliter"},
2831         {214,"grams-per-liter"},
2832         {215,"milligrams-per-liter"},
2833         {216,"micrograms-per-liter"},
2834         {217,"grams-per-cubic-meter"},
2835         {218,"milligrams-per-cubic-meter"},
2836         {219,"micrograms-per-cubic-meter"},
2837         {220,"nanograms-per-cubic-meter"},
2838         {221,"grams-per-cubic-centimeter"},
2839         {222,"becquerels"},
2840         {223,"kilobecquerels"},
2841         {224,"megabecquerels"},
2842         {225,"gray"},
2843         {226,"milligray"},
2844         {227,"microgray"},
2845         {228,"sieverts"},
2846         {229,"millisieverts"},
2847         {230,"microsieverts"},
2848         {231,"microsieverts-per-hour"},
2849         {232,"decibels-a"},
2850         {233,"nephelometric-turbidity-unit"},
2851         {234,"pH"},
2852         {235,"grams-per-square-meter"},
2853         {236,"minutes-per-degree-kelvin"},
2854         {0,NULL}
2855 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
2856    Enumerated values 256-65535 may be used by others subject to
2857    the procedures and constraints described in Clause 23. */
2858 };
2859
2860 static const value_string
2861 BACnetErrorCode [] = {
2862         {0,"other"},
2863         {1,"authentication-failed"},
2864         {2,"configuration-in-progress"},
2865         {3,"device-busy"},
2866         {4,"dynamic-creation-not-supported"},
2867         {5,"file-access-denied"},
2868         {6,"incompatible-security-levels"},
2869         {7,"inconsistent-parameters"},
2870         {8,"inconsistent-selection-criterion"},
2871         {9,"invalid-data-type"},
2872         {10,"invalid-file-access-method"},
2873         {11,"invalid-file-start-position"},
2874         {12,"invalid-operator-name"},
2875         {13,"invalid-parameter-data-type"},
2876         {14,"invalid-time-stamp"},
2877         {15,"key-generation-error"},
2878         {16,"missing-required-parameter"},
2879         {17,"no-objects-of-specified-type"},
2880         {18,"no-space-for-object"},
2881         {19,"no-space-to-add-list-element"},
2882         {20,"no-space-to-write-property"},
2883         {21,"no-vt-sessions-available"},
2884         {22,"property-is-not-a-list"},
2885         {23,"object-deletion-not-permitted"},
2886         {24,"object-identifier-already-exists"},
2887         {25,"operational-problem"},
2888         {26,"password-failure"},
2889         {27,"read-access-denied"},
2890         {28,"security-not-supported"},
2891         {29,"service-request-denied"},
2892         {30,"timeout"},
2893         {31,"unknown-object"},
2894         {32,"unknown-property"},
2895         {33,"removed enumeration"},
2896         {34,"unknown-vt-class"},
2897         {35,"unknown-vt-session"},
2898         {36,"unsupported-object-type"},
2899         {37,"value-out-of-range"},
2900         {38,"vt-session-already-closed"},
2901         {39,"vt-session-termination-failure"},
2902         {40,"write-access-denied"},
2903         {41,"character-set-not-supported"},
2904         {42,"invalid-array-index"},
2905         {43,"cov-subscription-failed"},
2906         {44,"not-cov-property"},
2907         {45,"optional-functionality-not-supported"},
2908         {46,"invalid-configuration-data"},
2909         {47,"datatype-not-supported"},
2910         {48,"duplicate-name"},
2911         {49,"duplicate-object-id"},
2912         {50,"property-is-not-an-array"},
2913         {73,"invalid-event-state"},
2914         {74,"no-alarm-configured"},
2915         {75,"log-buffer-full"},
2916         {76,"logged-value-purged"},
2917         {77,"no-property-specified"},
2918         {78,"not-configured-for-triggered-logging"},
2919         {79,"unknown-subscription"},
2920         {80,"parameter-out-of-range"},
2921         {81,"list-element-not-found"},
2922         {82,"busy"},
2923         {83,"communication-disabled"},
2924         {84,"success"},
2925         {85,"access-denied"},
2926         {86,"bad-destination-address"},
2927         {87,"bad-destination-device-id"},
2928         {88,"bad-signature"},
2929         {89,"bad-source-address"},
2930         {90,"bad-timestamp"},
2931         {91,"cannot-use-key"},
2932         {92,"cannot-verify-message-id"},
2933         {93,"correct-key-revision"},
2934         {94,"destination-device-id-required"},
2935         {95,"duplicate-message"},
2936         {96,"encryption-not-configured"},
2937         {97,"encryption-required"},
2938         {98,"incorrect-key"},
2939         {99,"invalid-key-data"},
2940         {100,"key-update-in-progress"},
2941         {101,"malformed-message"},
2942         {102,"not-key-server"},
2943         {103,"security-not-configured"},
2944         {104,"source-security-required"},
2945         {105,"too-many-keys"},
2946         {106,"unknown-authentication-type"},
2947         {107,"unknown-key"},
2948         {108,"unknown-key-revision"},
2949         {109,"unknown-source-message"},
2950         {110,"not-router-to-dnet"},
2951         {111,"router-busy"},
2952         {112,"unknown-network-message"},
2953         {113,"message-too-long"},
2954         {114,"security-error"},
2955         {115,"addressing-error"},
2956         {116,"write-bdt-failed"},
2957         {117,"read-bdt-failed"},
2958         {118,"register-foreign-device-failed"},
2959         {119,"read-fdt-failed"},
2960         {120,"delete-fdt-entry-failed"},
2961         {121,"distribute-broadcast-failed"},
2962         {122,"unknown-file-size"},
2963         {123,"abort-apdu-too-long"},
2964         {124,"abort-application-exceeded-reply-time"},
2965         {125,"abort-out-of-resources"},
2966         {126,"abort-tsm-timeout"},
2967         {127,"abort-window-size-out-of-range"},
2968         {128,"file-full"},
2969         {129,"inconsistent-configuration"},
2970         {130,"inconsistent-object-type"},
2971         {131,"internal-error"},
2972         {132,"not-configured"},
2973         {133,"out-of-memory"},
2974         {134,"value-too-long"},
2975         {135,"abort-insufficient-security"},
2976         {136,"abort-security-error"},
2977         {0, NULL}
2978 /* Enumerated values 0-255 are reserved for definition by ASHRAE.
2979    Enumerated values 256-65535 may be used by others subject to the
2980    procedures and constraints described in Clause 23. */
2981 };
2982
2983 static const value_string
2984 BACnetPropertyIdentifier [] = {
2985         {0,"acked-transition"},
2986         {1,"ack-required"},
2987         {2,"action"},
2988         {3,"action-text"},
2989         {4,"active-text"},
2990         {5,"active-vt-session"},
2991         {6,"alarm-value"},
2992         {7,"alarm-values"},
2993         {8,"all"},
2994         {9,"all-write-successful"},
2995         {10,"apdu-segment-timeout"},
2996         {11,"apdu-timeout"},
2997         {12,"application-software-version"},
2998         {13,"archive"},
2999         {14,"bias"},
3000         {15,"change-of-state-count"},
3001         {16,"change-of-state-time"},
3002         {17,"notification-class"},
3003         {18,"the property in this place was deleted"},
3004         {19,"controlled-variable-reference"},
3005         {20,"controlled-variable-units"},
3006         {21,"controlled-variable-value"},
3007         {22,"cov-increment"},
3008         {23,"datelist"},
3009         {24,"daylights-savings-status"},
3010         {25,"deadband"},
3011         {26,"derivative-constant"},
3012         {27,"derivative-constant-units"},
3013         {28,"description"},
3014         {29,"description-of-halt"},
3015         {30,"device-address-binding"},
3016         {31,"device-type"},
3017         {32,"effective-period"},
3018         {33,"elapsed-active-time"},
3019         {34,"error-limit"},
3020         {35,"event-enable"},
3021         {36,"event-state"},
3022         {37,"event-type"},
3023         {38,"exception-schedule"},
3024         {39,"fault-values"},
3025         {40,"feedback-value"},
3026         {41,"file-access-method"},
3027         {42,"file-size"},
3028         {43,"file-type"},
3029         {44,"firmware-revision"},
3030         {45,"high-limit"},
3031         {46,"inactive-text"},
3032         {47,"in-progress"},
3033         {48,"instance-of"},
3034         {49,"integral-constant"},
3035         {50,"integral-constant-units"},
3036         {51,"issue-confirmed-notifications"},
3037         {52,"limit-enable"},
3038         {53,"list-of-group-members"},
3039         {54,"list-of-object-property-references"},
3040         {55,"list-of-session-keys"},
3041         {56,"local-date"},
3042         {57,"local-time"},
3043         {58,"location"},
3044         {59,"low-limit"},
3045         {60,"manipulated-variable-reference"},
3046         {61,"maximum-output"},
3047         {62,"max-apdu-length-accepted"},
3048         {63,"max-info-frames"},
3049         {64,"max-master"},
3050         {65,"max-pres-value"},
3051         {66,"minimum-off-time"},
3052         {67,"minimum-on-time"},
3053         {68,"minimum-output"},
3054         {69,"min-pres-value"},
3055         {70,"model-name"},
3056         {71,"modification-date"},
3057         {72,"notify-type"},
3058         {73,"number-of-APDU-retries"},
3059         {74,"number-of-states"},
3060         {75,"object-identifier"},
3061         {76,"object-list"},
3062         {77,"object-name"},
3063         {78,"object-property-reference"},
3064         {79,"object-type"},
3065         {80,"optional"},
3066         {81,"out-of-service"},
3067         {82,"output-units"},
3068         {83,"event-parameters"},
3069         {84,"polarity"},
3070         {85,"present-value"},
3071         {86,"priority"},
3072         {87,"priority-array"},
3073         {88,"priority-for-writing"},
3074         {89,"process-identifier"},
3075         {90,"program-change"},
3076         {91,"program-location"},
3077         {92,"program-state"},
3078         {93,"proportional-constant"},
3079         {94,"proportional-constant-units"},
3080         {95,"protocol-conformance-class"},
3081         {96,"protocol-object-types-supported"},
3082         {97,"protocol-services-supported"},
3083         {98,"protocol-version"},
3084         {99,"read-only"},
3085         {100,"reason-for-halt"},
3086         {101,"recipient"},
3087         {102,"recipient-list"},
3088         {103,"reliability"},
3089         {104,"relinquish-default"},
3090         {105,"required"},
3091         {106,"resolution"},
3092         {107,"segmentation-supported"},
3093         {108,"setpoint"},
3094         {109,"setpoint-reference"},
3095         {110,"state-text"},
3096         {111,"status-flags"},
3097         {112,"system-status"},
3098         {113,"time-delay"},
3099         {114,"time-of-active-time-reset"},
3100         {115,"time-of-state-count-reset"},
3101         {116,"time-synchronization-recipients"},
3102         {117,"units"},
3103         {118,"update-interval"},
3104         {119,"utc-offset"},
3105         {120,"vendor-identifier"},
3106         {121,"vendor-name"},
3107         {122,"vt-class-supported"},
3108         {123,"weekly-schedule"},
3109         {124,"attempted-samples"},
3110         {125,"average-value"},
3111         {126,"buffer-size"},
3112         {127,"client-cov-increment"},
3113         {128,"cov-resubscription-interval"},
3114         {129,"current-notify-time"},
3115         {130,"event-time-stamp"},
3116         {131,"log-buffer"},
3117         {132,"log-device-object-property"},
3118         {133,"enable"}, /* per ANSI/ASHRAE 135-2004 addendum B */
3119         {134,"log-interval"},
3120         {135,"maximum-value"},
3121         {136,"minimum-value"},
3122         {137,"notification-threshold"},
3123         {138,"previous-notify-time"},
3124         {139,"protocol-revision"},
3125         {140,"records-since-notification"},
3126         {141,"record-count"},
3127         {142,"start-time"},
3128         {143,"stop-time"},
3129         {144,"stop-when-full"},
3130         {145,"total-record-count"},
3131         {146,"valid-samples"},
3132         {147,"window-interval"},
3133         {148,"window-samples"},
3134         {149,"maximum-value-time-stamp"},
3135         {150,"minimum-value-time-stamp"},
3136         {151,"variance-value"},
3137         {152,"active-cov-subscriptions"},
3138         {153,"backup-failure-timeout"},
3139         {154,"configuration-files"},
3140         {155,"database-revision"},
3141         {156,"direct-reading"},
3142         {157,"last-restore-time"},
3143         {158,"maintenance-required"},
3144         {159,"member-of"},
3145         {160,"mode"},
3146         {161,"operation-expected"},
3147         {162,"setting"},
3148         {163,"silenced"},
3149         {164,"tracking-value"},
3150         {165,"zone-members"},
3151         {166,"life-safety-alarm-values"},
3152         {167,"max-segments-accepted"},
3153         {168,"profile-name"},
3154         {169,"auto-slave-discovery"},
3155         {170,"manual-slave-address-binding"},
3156         {171,"slave-address-binding"},
3157         {172,"slave-proxy-enable"},
3158         {173,"last-notify-record"},             /* bug 4117 */
3159         {174,"schedule-default"},
3160         {175,"accepted-modes"},
3161         {176,"adjust-value"},
3162         {177,"count"},
3163         {178,"count-before-change"},
3164         {179,"count-change-time"},
3165         {180,"cov-period"},
3166         {181,"input-reference"},
3167         {182,"limit-monitoring-interval"},
3168         {183,"logging-device"},
3169         {184,"logging-record"},
3170         {185,"prescale"},
3171         {186,"pulse-rate"},
3172         {187,"scale"},
3173         {188,"scale-factor"},
3174         {189,"update-time"},
3175         {190,"value-before-change"},
3176         {191,"value-set"},
3177         {192,"value-change-time"},
3178         {193,"align-intervals"},
3179         {194,"group-member-names"},
3180         {195,"interval-offset"},
3181         {196,"last-restart-reason"},
3182         {197,"logging-type"},
3183         {198,"member-status-flags"},
3184         {199,"notification-period"},
3185         {200,"previous-notify-record"},
3186         {201,"requested-update-interval"},
3187         {202,"restart-notification-recipients"},
3188         {203,"time-of-device-restart"},
3189         {204,"time-synchronization-interval"},
3190         {205,"trigger"},
3191         {206,"UTC-time-synchronization-recipients"},
3192         {207,"node-subtype"},
3193         {208,"node-type"},
3194         {209,"structured-object-list"},
3195         {210,"subordinate-annotations"},
3196         {211,"subordinate-list"},
3197         {212,"actual-shed-level"},
3198         {213,"duty-window"},
3199         {214,"expected-shed-level"},
3200         {215,"full-duty-baseline"},
3201         {216,"node-subtype"},
3202         {217,"node-type"},
3203         {218,"requested-shed-level"},
3204         {219,"shed-duration"},
3205         {220,"shed-level-descriptions"},
3206         {221,"shed-levels"},
3207         {222,"state-description"},
3208         /* enumeration values 223-225 are unassigned */
3209         {226,"door-alarm-state"},
3210         {227,"door-extended-pulse-time"},
3211         {228,"door-members"},
3212         {229,"door-open-too-long-time"},
3213         {230,"door-pulse-time"},
3214         {231,"door-status"},
3215         {232,"door-unlock-delay-time"},
3216         {233,"lock-status"},
3217         {234,"masked-alarm-values"},
3218         {235,"secured-status"},
3219         /* enumeration values 236-243 are unassigned */
3220         {244,"absentee-limit"},         /* added with addenda 135-2008j */
3221         {245,"access-alarm-events"},
3222         {246,"access-doors"},
3223         {247,"access-event"},
3224         {248,"access-event-authentication-factor"},
3225         {249,"access-event-credential"},
3226         {250,"access-event-time"},
3227         {251,"access-transaction-events"},
3228         {252,"accompaniment"},
3229         {253,"accompaniment-time"},
3230         {254,"activation-time"},
3231         {255,"active-authentication-policy"},
3232         {256,"assigned-access-rights"},
3233         {257,"authentication-factors"},
3234         {258,"authentication-policy-list"},
3235         {259,"authentication-policy-names"},
3236         {260,"authentication-status"},
3237         {261,"authorization-mode"},
3238         {262,"belongs-to"},
3239         {263,"credential-disable"},
3240         {264,"credential-status"},
3241         {265,"credentials"},
3242         {266,"credentials-in-zone"},
3243         {267,"days-remaining"},
3244         {268,"entry-points"},
3245         {269,"exit-points"},
3246         {270,"expiry-time"},
3247         {271,"extended-time-enable"},
3248         {272,"failed-attempt-events"},
3249         {273,"failed-attempts"},
3250         {274,"failed-attempts-time"},
3251         {275,"last-access-event"},
3252         {276,"last-access-point"},
3253         {277,"last-credential-added"},
3254         {278,"last-credential-added-time"},
3255         {279,"last-credential-removed"},
3256         {280,"last-credential-removed-time"},
3257         {281,"last-use-time"},
3258         {282,"lockout"},
3259         {283,"lockout-relinquish-time"},
3260         {284,"master-exemption"},
3261         {285,"max-failed-attempts"},
3262         {286,"members"},
3263         {287,"muster-point"},
3264         {288,"negative-access-rules"},
3265         {289,"number-of-authentication-policies"},
3266         {290,"occupancy-count"},
3267         {291,"occupancy-count-adjust"},
3268         {292,"occupancy-count-enable"},
3269         {293,"occupancy-exemption"},
3270         {294,"occupancy-lower-limit"},
3271         {295,"occupancy-lower-limit-enforced"},
3272         {296,"occupancy-state"},
3273         {297,"occupancy-upper-limit"},
3274         {298,"occupancy-upper-limit-enforced"},
3275         {299,"passback-exemption"},
3276         {300,"passback-mode"},
3277         {301,"passback-timeout"},
3278         {302,"positive-access-rules"},
3279         {303,"reason-for-disable"},
3280         {304,"supported-formats"},
3281         {305,"supported-format-classes"},
3282         {306,"threat-authority"},
3283         {307,"threat-level"},
3284         {308,"trace-flag"},
3285         {309,"transaction-notification-class"},
3286         {310,"user-external-identifier"},
3287         {311,"user-information-reference"},
3288         /* enumeration values 312-316 are unassigned */
3289         {317,"user-name"},
3290         {318,"user-type"},
3291         {319,"uses-remaining"},
3292         {320,"zone-from"},
3293         {321,"zone-to"},
3294         {322,"access-event-tag"},
3295         {323,"global-identifier"},
3296         /* enumeration values 324-325 reserved for future addenda */
3297         {326,"verification-time"},
3298         {327,"base-device-security-policy"},
3299         {328,"distribution-key-revision"},
3300         {329,"do-not-hide"},
3301         {330,"key-sets"},
3302         {331,"last-key-server"},
3303         {332,"network-access-security-policies"},
3304         {333,"packet-reorder-time"},
3305         {334,"security-pdu-timeout"},
3306         {335,"security-time-window"},
3307         {336,"supported-security-algorithms"},
3308         {337,"update-key-set-timeout"},
3309         {338,"backup-and-restore-state"},
3310         {339,"backup-preparation-time"},
3311         {340,"restore-completion-time"},
3312         {341,"restore-preparation-time"},
3313         {342,"bit-mask"},               /* addenda 135-2008w */
3314         {343,"bit-text"},
3315         {344,"is-utc"},
3316         {345,"group-members"},
3317         {346,"group-member-names"},
3318         {347,"member-status-flags"},
3319         {348,"requested-update-interval"},
3320         {349,"covu-period"},
3321         {350,"covu-recipients"},
3322         {351,"event-message-texts"},
3323         {0, NULL}
3324 /* Enumerated values 0-511 are reserved for definition by ASHRAE.
3325    Enumerated values 512-4194303 may be used by others subject to
3326    the procedures and constraints described in Clause 23. */
3327 };
3328
3329 static const value_string
3330 BACnetBinaryPV [] = {
3331         {0,"inactive"},
3332         {1,"active"},
3333         {0,NULL}
3334 };
3335
3336
3337 #define ANSI_X34 0
3338 #define IBM_MS_DBCS 1
3339 #define JIS_C_6226 2
3340 #define ISO_10646_UCS4 3
3341 #define ISO_10646_UCS2 4
3342 #define ISO_18859_1 5
3343 static const value_string
3344 BACnetCharacterSet [] = {
3345         {ANSI_X34,      "ANSI X3.4 / UTF-8 (since 2010)"},
3346         {IBM_MS_DBCS,   "IBM/Microsoft DBCS"},
3347         {JIS_C_6226,    "JIS C 6226"},
3348         {ISO_10646_UCS4, "ISO 10646(UCS-4)"},
3349         {ISO_10646_UCS2, "ISO 10646(UCS-2)"},
3350         {ISO_18859_1,   "ISO 18859-1"},
3351         {0,             NULL}
3352 };
3353
3354 static const value_string
3355 BACnetStatusFlags [] = {
3356         {0,"in-alarm"},
3357         {1,"fault"},
3358         {2,"overridden"},
3359         {3,"out-of-service"},
3360         {0,NULL}
3361 };
3362
3363 static const value_string
3364 BACnetMessagePriority [] = {
3365         {0,"normal"},
3366         {1,"urgent"},
3367         {0,NULL}
3368 };
3369
3370 static const value_string
3371 BACnetAcknowledgementFilter [] = {
3372         {0,"all"},
3373         {1,"acked"},
3374         {2,"not-acked"},
3375         {0,NULL}
3376 };
3377
3378 static const value_string
3379 BACnetResultFlags [] = {
3380         {0,"firstitem"},
3381         {1,"lastitem"},
3382         {2,"moreitems"},
3383         {0,NULL}
3384 };
3385
3386 static const value_string
3387 BACnetRelationSpecifier [] = {
3388         {0,"equal"},
3389         {1,"not-equal"},
3390         {2,"less-than"},
3391         {3,"greater-than"},
3392         {4,"less-than-or-equal"},
3393         {5,"greater-than-or-equal"},
3394         {0,NULL}
3395 };
3396
3397 static const value_string
3398 BACnetSelectionLogic [] = {
3399         {0,"and"},
3400         {1,"or"},
3401         {2,"all"},
3402         {0,NULL}
3403 };
3404
3405 static const value_string
3406 BACnetEventStateFilter [] = {
3407         {0,"offnormal"},
3408         {1,"fault"},
3409         {2,"normal"},
3410         {3,"all"},
3411         {4,"active"},
3412         {0,NULL}
3413 };
3414
3415 static const value_string
3416 BACnetEventTransitionBits [] = {
3417         {0,"to-offnormal"},
3418         {1,"to-fault"},
3419         {2,"to-normal"},
3420         {0,NULL}
3421 };
3422
3423 static const value_string
3424 BACnetSegmentation [] = {
3425         {0,"segmented-both"},
3426         {1,"segmented-transmit"},
3427         {2,"segmented-receive"},
3428         {3,"no-segmentation"},
3429         {0,NULL}
3430 };
3431
3432 static const value_string
3433 BACnetSilencedState [] = {
3434         {0,"unsilenced"},
3435         {1,"audible-silenced"},
3436         {2,"visible-silenced"},
3437         {3,"all-silenced"},
3438         {0,NULL}
3439 };
3440
3441 static const value_string
3442 BACnetDeviceStatus [] = {
3443         {0,"operational"},
3444         {1,"operational-read-only"},
3445         {2,"download-required"},
3446         {3,"download-in-progress"},
3447         {4,"non-operational"},
3448         {5,"backup-in-progress"},
3449         {0,NULL}
3450 };
3451
3452 static const value_string
3453 BACnetEnableDisable [] = {
3454         {0,"enable"},
3455         {1,"disable"},
3456         {2,"disable-initiation"},
3457         {0,NULL}
3458 };
3459
3460 static const value_string
3461 months [] = {
3462         {1,"January" },
3463         {2,"February" },
3464         {3,"March" },
3465         {4,"April" },
3466         {5,"May" },
3467         {6,"June" },
3468         {7,"July" },
3469         {8,"August" },
3470         {9,"September" },
3471         {10,"October" },
3472         {11,"November" },
3473         {12,"December" },
3474         {255,"any month" },
3475         {0,NULL }
3476 };
3477
3478 static const value_string
3479 weekofmonth [] = {
3480         {1,"days numbered 1-7" },
3481         {2,"days numbered 8-14" },
3482         {3,"days numbered 15-21" },
3483         {4,"days numbered 22-28" },
3484         {5,"days numbered 29-31" },
3485         {6,"last 7 days of this month" },
3486         {255,"any week of this month" },
3487         {0,NULL }
3488 };
3489
3490 /* note: notification class object recipient-list uses
3491    different day-of-week enum */
3492 static const value_string
3493 day_of_week [] = {
3494         {1,"Monday" },
3495         {2,"Tuesday" },
3496         {3,"Wednesday" },
3497         {4,"Thursday" },
3498         {5,"Friday" },
3499         {6,"Saturday" },
3500         {7,"Sunday" },
3501         {255,"any day of week" },
3502         {0,NULL }
3503 };
3504
3505 static const value_string
3506 BACnetErrorClass [] = {
3507         {0,"device" },
3508         {1,"object" },
3509         {2,"property" },
3510         {3,"resources" },
3511         {4,"security" },
3512         {5,"services" },
3513         {6,"vt" },
3514         {7,"communication" },
3515         {0,NULL }
3516 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
3517    Enumerated values64-65535 may be used by others subject to
3518    the procedures and constraints described in Clause 23. */
3519 };
3520
3521 static const value_string
3522 BACnetVTClass [] = {
3523         {0,"default-terminal" },
3524         {1,"ansi-x3-64" },
3525         {2,"dec-vt52" },
3526         {3,"dec-vt100" },
3527         {4,"dec-vt200" },
3528         {5,"hp-700-94" },
3529         {6,"ibm-3130" },
3530         {0,NULL }
3531 };
3532
3533 static const value_string
3534 BACnetEventType [] = {
3535         {0,"change-of-bitstring" },
3536         {1,"change-of-state" },
3537         {2,"change-of-value" },
3538         {3,"command-failure" },
3539         {4,"floating-limit" },
3540         {5,"out-of-range" },
3541         {6,"complex-event-type" },
3542         {7,"buffer-ready" },
3543         {8,"change-of-life-safety" },
3544         {9,"extended" },
3545         {10,"buffer-ready" },
3546         {11,"unsigned-range" },
3547         {14,"double-out-of-range"},             /* added with addenda 135-2008w */
3548         {15,"signed-out-of-range"},
3549         {16,"unsigned-out-of-range"},
3550         {17,"change-of-characterstring"},
3551         {18,"change-of-status-flags"},
3552         {0,NULL }
3553 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
3554    Enumerated values 64-65535 may be used by others subject to
3555    the procedures and constraints described in Clause 23.
3556    It is expected that these enumerated values will correspond
3557    to the use of the complex-event-type CHOICE [6] of the
3558    BACnetNotificationParameters production. */
3559 };
3560
3561 static const value_string
3562 BACnetEventState [] = {
3563         {0,"normal" },
3564         {1,"fault" },
3565         {2,"offnormal" },
3566         {3,"high-limit" },
3567         {4,"low-limit" },
3568         {5,"life-safety-alarm" },
3569         {0,NULL }
3570 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
3571    Enumerated values 64-65535 may be used by others subject to
3572    the procedures and constraints described in Clause 23.  */
3573 };
3574
3575 static const value_string
3576 BACnetLogStatus [] = {
3577         {0,"log-disabled" },
3578         {1,"buffer-purged" },
3579         {2,"log-interrupted"},
3580         {0,NULL }
3581 };
3582
3583 static const value_string
3584 BACnetMaintenance [] = {
3585         {0,"none" },
3586         {1,"periodic-test" },
3587         {2,"need-service-operational" },
3588         {3,"need-service-inoperative" },
3589         {0,NULL }
3590 };
3591
3592 static const value_string
3593 BACnetNotifyType [] = {
3594         {0,"alarm" },
3595         {1,"event" },
3596         {2,"ack-notification" },
3597         {0,NULL }
3598 };
3599
3600 static const value_string
3601 BACnetServicesSupported [] = {
3602         {0,"acknowledgeAlarm"},
3603         {1,"confirmedCOVNotification"},
3604         {2,"confirmedEventNotification"},
3605         {3,"getAlarmSummary"},
3606         {4,"getEnrollmentSummary"},
3607         {5,"subscribeCOV"},
3608         {6,"atomicReadFile"},
3609         {7,"atomicWriteFile"},
3610         {8,"addListElement"},
3611         {9,"removeListElement"},
3612         {10,"createObject"},
3613         {11,"deleteObject"},
3614         {12,"readProperty"},
3615         {13,"readPropertyConditional"},
3616         {14,"readPropertyMultiple"},
3617         {15,"writeProperty"},
3618         {16,"writePropertyMultiple"},
3619         {17,"deviceCommunicationControl"},
3620         {18,"confirmedPrivateTransfer"},
3621         {19,"confirmedTextMessage"},
3622         {20,"reinitializeDevice"},
3623         {21,"vtOpen"},
3624         {22,"vtClose"},
3625         {23,"vtData"},
3626         {24,"authenticate"},
3627         {25,"requestKey"},
3628         {26,"i-Am"},
3629         {27,"i-Have"},
3630         {28,"unconfirmedCOVNotification"},
3631         {29,"unconfirmedEventNotification"},
3632         {30,"unconfirmedPrivateTransfer"},
3633         {31,"unconfirmedTextMessage"},
3634         {32,"timeSynchronization"},
3635         {33,"who-Has"},
3636         {34,"who-Is"},
3637         {35,"readRange"},
3638         {36,"utcTimeSynchronization"},
3639         {37,"lifeSafetyOperation"},
3640         {38,"subscribeCOVProperty"},
3641         {39,"getEventInformation"},
3642         {0, NULL}
3643 };
3644
3645 static const value_string
3646 BACnetPropertyStates [] = {
3647         {0,"boolean-value"},
3648         {1,"binary-value"},
3649         {2,"event-type"},
3650         {3,"polarity"},
3651         {4,"program-change"},
3652         {5,"program-state"},
3653         {6,"reason-for-halt"},
3654         {7,"reliability"},
3655         {8,"state"},
3656         {9,"system-status"},
3657         {10,"units"},
3658         {11,"unsigned-value"},
3659         {12,"life-safety-mode"},
3660         {13,"life-safety-state"},
3661         {14,"restart-reason"},
3662         {15,"door-alarm-state"},
3663         {16,"action"},
3664         {17,"door-secured-status"},
3665         {18,"door-status"},
3666         {19,"door-value"},
3667         {20,"file-access-method"},
3668         {21,"lock-status"},
3669         {22,"life-safety-operation"},
3670         {23,"maintenance"},
3671         {24,"node-type"},
3672         {25,"notify-type"},
3673         {26,"security-level"},
3674         {27,"shed-state"},
3675         {28,"silenced-state"},
3676         /* context tag 29 reserved for future addenda */
3677         {29,"unknown-29"},
3678         {30,"access-event"},
3679         {31,"zone-occupancy-state"},
3680         {32,"access-credential-disable-reason"},
3681         {33,"access-credential-disable"},
3682         {34,"authentication-status"},
3683         {35,"unknown-35"},
3684         {36,"backup-state"},
3685         {0,NULL}
3686 /* Tag values 0-63 are reserved for definition by ASHRAE.
3687    Tag values of 64-254 may be used by others to accommodate
3688    vendor specific properties that have discrete or enumerated values,
3689    subject to the constraints described in Clause 23. */
3690 };
3691
3692 static const value_string
3693 BACnetProgramError [] = {
3694         {0,"normal"},
3695         {1,"load-failed"},
3696         {2,"internal"},
3697         {3,"program"},
3698         {4,"other"},
3699         {0,NULL}
3700 /* Enumerated values 0-63 are reserved for definition by ASHRAE.
3701    Enumerated values 64-65535 may be used by others subject to
3702    the procedures and constraints described in Clause 23. */
3703 };
3704
3705 static const value_string
3706 BACnetProgramRequest [] = {
3707         {0,"ready"},
3708         {1,"load"},
3709         {2,"run"},
3710         {3,"halt"},
3711         {4,"restart"},
3712         {4,"unload"},
3713         {0,NULL}
3714 };
3715
3716 static const value_string
3717 BACnetProgramState [] = {
3718         {0,"idle"},
3719         {1,"loading"},
3720         {2,"running"},
3721         {3,"waiting"},
3722         {4,"halted"},
3723         {4,"unloading"},
3724         {0,NULL}
3725 };
3726
3727 static const value_string
3728 BACnetReinitializedStateOfDevice [] = {
3729         {0,"coldstart"},
3730         {1,"warmstart"},
3731         {2,"startbackup"},
3732         {3,"endbackup"},
3733         {4,"startrestore"},
3734         {5,"endrestore"},
3735         {6,"abortrestore"},
3736         {0,NULL}
3737 };
3738
3739 static const value_string
3740 BACnetPolarity [] = {
3741         {0,"normal"},
3742         {1,"reverse"},
3743         {0,NULL}
3744 };
3745
3746 static const value_string
3747 BACnetTagNames[] = {
3748         { 5, "Extended Value" },
3749         { 6, "Opening Tag" },
3750         { 7, "Closing Tag" },
3751         { 0, NULL }
3752 };
3753
3754 static const value_string
3755 BACnetReadRangeOptions[] = {
3756         { 3, "range byPosition" },
3757         { 4, "range byTime" },
3758         { 5, "range timeRange" },
3759         { 6, "range bySequenceNumber" },
3760         { 7, "range byTime" },
3761         { 0, NULL }
3762 };
3763
3764 /* Present_Value for Load Control Object */
3765 static const value_string
3766 BACnetShedState[] = {
3767         { 0, "shed-inactive" },
3768         { 1, "shed-request-pending" },
3769         { 2, "shed-compliant" },
3770         { 3, "shed-non-compliant" },
3771         { 0, NULL }
3772 };
3773
3774 static const value_string
3775 BACnetNodeType [] = {
3776         { 0, "unknown" },
3777         { 1, "system" },
3778         { 2, "network" },
3779         { 3, "device" },
3780         { 4, "organizational" },
3781         { 5, "area" },
3782         { 6, "equipment" },
3783         { 7, "point" },
3784         { 8, "collection" },
3785         { 9, "property" },
3786         { 10, "functional" },
3787         { 11, "other" },
3788         { 0, NULL }
3789 };
3790
3791 static const value_string
3792 BACnetLoggingType [] = {
3793         { 0, "polled" },
3794         { 1, "cov" },
3795         { 2, "triggered" },
3796         { 0, NULL }
3797 };
3798
3799 static const value_string
3800 BACnetDoorStatus [] = {
3801         { 0, "closed" },
3802         { 1, "opened" },
3803         { 2, "unknown" },
3804         { 0, NULL }
3805 };
3806
3807 static const value_string
3808 BACnetLockStatus [] = {
3809         { 0, "locked" },
3810         { 1, "unlocked" },
3811         { 2, "fault" },
3812         { 3, "unknown" },
3813         { 0, NULL }
3814 };
3815
3816 static const value_string
3817 BACnetDoorSecuredStatus [] = {
3818         { 0, "secured" },
3819         { 1, "unsecured" },
3820         { 2, "unknown" },
3821         { 0, NULL }
3822 };
3823
3824 static const value_string
3825 BACnetDoorAlarmState [] = {
3826         { 0, "normal" },
3827         { 1, "alarm" }, 
3828         { 2, "door-open-too-long" },
3829         { 3, "forced-open" },
3830         { 4, "tamper" },
3831         { 5, "door-fault" },
3832         { 6, "lock-down" },
3833         { 7, "free-access" },
3834         { 8, "egress-open" },
3835         { 0, NULL }
3836 };
3837
3838 static const value_string
3839 BACnetAccumulatorStatus [] = {
3840         { 0, "normal" },
3841         { 1, "starting" },
3842         { 2, "recovered" },
3843         { 3, "abnormal" },
3844         { 4, "failed" },
3845         { 0, NULL }
3846 };
3847
3848 static const value_string
3849 BACnetVendorIdentifiers [] = {
3850         { 0, "ASHRAE" },
3851         { 1, "NIST" },
3852         { 2, "The Trane Company" },
3853         { 3, "McQuay International" },
3854         { 4, "PolarSoft" },
3855         { 5, "Johnson Controls, Inc." },
3856         { 6, "American Auto-Matrix" },
3857         { 7, "Siemens Building Technologies, Ltd., Landis & Staefa Division Europe" },
3858         { 8, "Delta Controls" },
3859         { 9, "Siemens Building Technologies, Inc." },
3860         { 10, "Tour Andover Controls Corporation" },
3861         { 11, "TAC" },
3862         { 12, "Orion Analysis Corporation" },
3863         { 13, "Teletrol Systems Inc." },
3864         { 14, "Cimetrics Technology" },
3865         { 15, "Cornell University" },
3866         { 16, "United Technologies Carrier" },
3867         { 17, "Honeywell Inc." },
3868         { 18, "Alerton / Honeywell" },
3869         { 19, "TAC AB" },
3870         { 20, "Hewlett-Packard Company" },
3871         { 21, "Dorsette's Inc." },
3872         { 22, "Cerberus AG" },
3873         { 23, "York Controls Group" },
3874         { 24, "Automated Logic Corporation" },
3875         { 25, "CSI Control Systems International" },
3876         { 26, "Phoenix Controls Corporation" },
3877         { 27, "Innovex Technologies, Inc." },
3878         { 28, "KMC Controls, Inc." },
3879         { 29, "Xn Technologies, Inc." },
3880         { 30, "Hyundai Information Technology Co., Ltd." },
3881         { 31, "Tokimec Inc." },
3882         { 32, "Simplex" },
3883         { 33, "North Communications Limited" },
3884         { 34, "Notifier" },
3885         { 35, "Reliable Controls Corporation" },
3886         { 36, "Tridium Inc." },
3887         { 37, "Sierra Monitor Corp." },
3888         { 38, "Silicon Energy" },
3889         { 39, "Kieback & Peter GmbH & Co KG" },
3890         { 40, "Anacon Systems, Inc." },
3891         { 41, "Systems Controls & Instruments, LLC" },
3892         { 42, "Lithonia Lighting" },
3893         { 43, "Micropower Manufacturing" },
3894         { 44, "Matrix Controls" },
3895         { 45, "METALAIRE" },
3896         { 46, "ESS Engineering" },
3897         { 47, "Sphere Systems Pty Ltd." },
3898         { 48, "Walker Technologies Corporation" },
3899         { 49, "H I Solutions, Inc." },
3900         { 50, "MBS GmbH" },
3901         { 51, "SAMSON AG" },
3902         { 52, "Badger Meter Inc." },
3903         { 53, "DAIKIN Industries Ltd." },
3904         { 54, "NARA Controls Inc." },
3905         { 55, "Mammoth Inc." },
3906         { 56, "Liebert Corporation" },
3907         { 57, "SEMCO Incorporated" },
3908         { 58, "Air Monitor Corporation" },
3909         { 59, "TRIATEK, Inc." },
3910         { 60, "NexLight" },
3911         { 61, "Multistack" },
3912         { 62, "TSI Incorporated" },
3913         { 63, "Weather-Rite, Inc." },
3914         { 64, "Dunham-Bush" },
3915         { 65, "Reliance Electric" },
3916         { 66, "LCS Inc." },
3917         { 67, "Regulator Australia PTY Ltd." },
3918         { 68, "Touch-Plate Lighting Controls" },
3919         { 69, "Amann GmbH" },
3920         { 70, "RLE Technologies" },
3921         { 71, "Cardkey Systems" },
3922         { 72, "SECOM Co., Ltd." },
3923         { 73, "ABB Gebaudetechnik AG Bereich NetServ" },
3924         { 74, "KNX Association cvba" },
3925         { 75, "Institute of Electrical Installation Engineers of Japan (IEIEJ)" },
3926         { 76, "Nohmi Bosai, Ltd." },
3927         { 77, "Carel S.p.A." },
3928         { 78, "AirSense Technology, Inc." },
3929         { 79, "Hochiki Corporation" },
3930         { 80, "Fr. Sauter AG" },
3931         { 81, "Matsushita Electric Works, Ltd." },
3932         { 82, "Mitsubishi Electric Corporation, Inazawa Works" },
3933         { 83, "Mitsubishi Heavy Industries, Ltd." },
3934         { 84, "ITT Bell & Gossett" },
3935         { 85, "Yamatake Building Systems Co., Ltd." },
3936         { 86, "The Watt Stopper, Inc." },
3937         { 87, "Aichi Tokei Denki Co., Ltd." },
3938         { 88, "Activation Technologies, LLC" },
3939         { 89, "Saia-Burgess Controls, Ltd." },
3940         { 90, "Hitachi, Ltd." },
3941         { 91, "Novar Corp./Trend Control Systems Ltd." },
3942         { 92, "Mitsubishi Electric Lighting Corporation" },
3943         { 93, "Argus Control Systems, Ltd." },
3944         { 94, "Kyuki Corporation" },
3945         { 95, "Richards-Zeta Building Intelligence, Inc." },
3946         { 96, "Scientech R&D, Inc." },
3947         { 97, "VCI Controls, Inc." },
3948         { 98, "Toshiba Corporation" },
3949         { 99, "Mitsubishi Electric Corporation Air Conditioning & Refrigeration Systems Works" },
3950         { 100, "Custom Mechanical Equipment, LLC" },
3951         { 101, "ClimateMaster" },
3952         { 102, "ICP Panel-Tec, Inc." },
3953         { 103, "D-Tek Controls" },
3954         { 104, "NEC Engineering, Ltd." },
3955         { 105, "PRIVA BV" },
3956         { 106, "Meidensha Corporation" },
3957         { 107, "JCI Systems Integration Services" },
3958         { 108, "Freedom Corporation" },
3959         { 109, "Neuberger Gebaudeautomation GmbH" },
3960         { 110, "Sitronix" },
3961         { 111, "Leviton Manufacturing" },
3962         { 112, "Fujitsu Limited" },
3963         { 113, "Emerson Network Power" },
3964         { 114, "S. A. Armstrong, Ltd." },
3965         { 115, "Visonet AG" },
3966         { 116, "M&M Systems, Inc." },
3967         { 117, "Custom Software Engineering" },
3968         { 118, "Nittan Company, Limited" },
3969         { 119, "Elutions Inc. (Wizcon Systems SAS)" },
3970         { 120, "Pacom Systems Pty., Ltd." },
3971         { 121, "Unico, Inc." },
3972         { 122, "Ebtron, Inc." },
3973         { 123, "Scada Engine" },
3974         { 124, "AC Technology Corporation" },
3975         { 125, "Eagle Technology" },
3976         { 126, "Data Aire, Inc." },
3977         { 127, "ABB, Inc." },
3978         { 128, "Transbit Sp. z o. o." },
3979         { 129, "Toshiba Carrier Corporation" },
3980         { 130, "Shenzhen Junzhi Hi-Tech Co., Ltd." },
3981         { 131, "Tokai Soft" },
3982         { 132, "Lumisys" },
3983         { 133, "Veris Industries" },
3984         { 134, "Centaurus Prime" },
3985         { 135, "Sand Network Systems" },
3986         { 136, "Regulvar, Inc." },
3987         { 137, "Fastek International, Ltd." },
3988         { 138, "PowerCold Comfort Air Solutions, Inc." },
3989         { 139, "I Controls" },
3990         { 140, "Viconics Electronics, Inc." },
3991         { 141, "Yaskawa Electric America, Inc." },
3992         { 142, "Plueth Regelsysteme" },
3993         { 143, "Digitale Mess- und Steuersysteme AG" },
3994         { 144, "Fujitsu General Limited" },
3995         { 145, "Project Engineering S.r.l." },
3996         { 146, "Sanyo Electric Co., Ltd." },
3997         { 147, "Integrated Information Systems, Inc." },
3998         { 148, "Temco Controls, Ltd." },
3999         { 149, "Airtek Technologies, Inc." },
4000         { 150, "Advantech Corporation" },
4001         { 151, "Titan Products, Ltd." },
4002         { 152, "Regel Partners" },
4003         { 153, "National Environmental Product" },
4004         { 154, "Unitec Corporation" },
4005         { 155, "Kanden Engineering Company" },
4006         { 156, "Messner Gebaudetechnik GmbH" },
4007         { 157, "Integrated.CH" },
4008         { 158, "EH Price Limited" },
4009         { 159, "SE-Elektronic GmbH" },
4010         { 160, "Rockwell Automation" },
4011         { 161, "Enflex Corp." },
4012         { 162, "ASI Controls" },
4013         { 163, "SysMik GmbH Dresden" },
4014         { 164, "HSC Regelungstechnik GmbH" },
4015         { 165, "Smart Temp Australia Pty. Ltd." },
4016         { 166, "PCI Lighting Control Systems" },
4017         { 167, "Duksan Mecasys Co., Ltd." },
4018         { 168, "Fuji IT Co., Ltd." },
4019         { 169, "Vacon Plc" },
4020         { 170, "Leader Controls" },
4021         { 171, "Cylon Controls, Ltd." },
4022         { 172, "Compas" },
4023         { 173, "Mitsubishi Electric Building Techno-Service Co., Ltd." },
4024         { 174, "Building Control Integrators" },
4025         { 175, "ITG Worldwide (M) Sdn Bhd" },
4026         { 176, "Lutron Electronics Co., Inc." },
4027         { 177, "Cooper-Atkins Corporation" },
4028         { 178, "LOYTEC Electronics GmbH" },
4029         { 179, "ProLon" },
4030         { 180, "Mega Controls Limited" },
4031         { 181, "Micro Control Systems, Inc." },
4032         { 182, "Kiyon, Inc." },
4033         { 183, "Dust Networks" },
4034         { 184, "Advanced Building Automation Systems" },
4035         { 185, "Hermos AG" },
4036         { 186, "CEZIM" },
4037         { 187, "Softing" },
4038         { 188, "Lynxspring" },
4039         { 189, "Schneider Toshiba Inverter Europe" },
4040         { 190, "Danfoss Drives A/S" },
4041         { 191, "Eaton Corporation" },
4042         { 192, "Matyca S.A." },
4043         { 193, "Botech AB" },
4044         { 194, "Noveo, Inc." },
4045         { 195, "AMEV" },
4046         { 196, "Yokogawa Electric Corporation" },
4047         { 197, "GFR Gesellschaft fur Regelungstechnik" },
4048         { 198, "Exact Logic" },
4049         { 199, "Mass Electronics Pty Ltd dba Innotech Control Systems Australia" },
4050         { 200, "Kandenko Co., Ltd." },
4051         { 201, "DTF, Daten-Technik Fries" },
4052         { 202, "Klimasoft, Ltd." },
4053         { 203, "Toshiba Schneider Inverter Corporation" },
4054         { 204, "Control Applications, Ltd." },
4055         { 205, "KDT Systems Co., Ltd." },
4056         { 206, "Onicon Incorporated" },
4057         { 207, "Automation Displays, Inc." },
4058         { 208, "Control Solutions, Inc." },
4059         { 209, "Remsdaq Limited" },
4060         { 210, "NTT Facilities, Inc." },
4061         { 211, "VIPA GmbH" },
4062         { 212, "TSC21 Association of Japan" },
4063         { 213, "BBP Energie Ltee" },
4064         { 214, "HRW Limited" },
4065         { 215, "Lighting Control & Design, Inc." },
4066         { 216, "Mercy Electronic and Electrical Industries" },
4067         { 217, "Samsung SDS Co., Ltd" },
4068         { 218, "Impact Facility Solutions, Inc." },
4069         { 219, "Aircuity" },
4070         { 220, "Control Techniques, Ltd." },
4071         { 221, "Evolve Control Systems, LLC" },
4072         { 222, "WAGO Kontakttechnik GmbH & Co. KG" },
4073         { 223, "Cerus Industrial" },
4074         { 224, "Chloride Power Protection Company" },
4075         { 225, "Computrols, Inc." },
4076         { 226, "Phoenix Contact GmbH & Co. KG" },
4077         { 227, "Grundfos Management A/S" },
4078         { 228, "Ridder Drive Systems" },
4079         { 229, "Soft Device SDN BHD" },
4080         { 230, "Integrated Control Technology Limited" },
4081         { 231, "AIRxpert Systems, Inc." },
4082         { 232, "Microtrol Limited" },
4083         { 233, "Red Lion Controls" },
4084         { 234, "Digital Electronics Corporation" },
4085         { 235, "Ennovatis GmbH" },
4086         { 236, "Serotonin Software Technologies, Inc." },
4087         { 237, "LS Industrial Systems Co., Ltd." },
4088         { 238, "Square D Company" },
4089         { 239, "S Squared Innovations, Inc." },
4090         { 240, "Aricent Ltd." },
4091         { 241, "EtherMetrics, LLC" },
4092         { 242, "Industrial Control Communications, Inc." },
4093         { 243, "Paragon Controls, Inc." },
4094         { 244, "A. O. Smith Corporation" },
4095         { 245, "Contemporary Control Systems, Inc." },
4096         { 246, "Intesis Software SL" },
4097         { 247, "Ingenieurgesellschaft N. Hartleb mbH" },
4098         { 248, "Heat-Timer Corporation" },
4099         { 249, "Ingrasys Technology, Inc." },
4100         { 250, "Costerm Building Automation" },
4101         { 251, "Wilo AG" },
4102         { 252, "Embedia Technologies Corp." },
4103         { 253, "Technilog" },
4104         { 254, "HR Controls Ltd. & Co. KG" },
4105         { 255, "Lennox International, Inc." },
4106         { 256, "RK-Tec Rauchklappen-Steuerungssysteme GmbH & Co. KG" },
4107         { 257, "Thermomax, Ltd." },
4108         { 258, "ELCON Electronic Control, Ltd." },
4109         { 259, "Larmia Control AB" },
4110         { 260, "BACnet Stack at SourceForge" },
4111         { 261, "G4S Security Services A/S" },
4112         { 262, "Sitek S.p.A." },
4113         { 263, "Cristal Controles" },
4114         { 264, "Regin AB" },
4115         { 265, "Dimension Software, Inc. " },
4116         { 266, "SynapSense Corporation" },
4117         { 267, "Beijing Nantree Electronic Co., Ltd." },
4118         { 268, "Camus Hydronics Ltd." },
4119         { 269, "Kawasaki Heavy Industries, Ltd. " },
4120         { 270, "Critical Environment Technologies" },
4121         { 271, "ILSHIN IBS Co., Ltd." },
4122         { 272, "ELESTA Energy Control AG" },
4123         { 273, "KROPMAN Installatietechniek" },
4124         { 274, "Baldor Electric Company" },
4125         { 275, "INGA mbH" },
4126         { 276, "GE Consumer & Industrial" },
4127         { 277, "Functional Devices, Inc." },
4128         { 278, "ESAC" },
4129         { 279, "M-System Co., Ltd." },
4130         { 280, "Yokota Co., Ltd." },
4131         { 281, "Hitranse Technology Co., LTD" },
4132         { 282, "Federspiel Controls" },
4133         { 283, "Kele, Inc." },
4134         { 284, "Opera Electronics, Inc." },
4135         { 285, "Gentec" },
4136         { 286, "Embedded Science Labs, LLC" },
4137         { 287, "Parker Hannifin Corporation" },
4138         { 288, "MaCaPS International Limited" },
4139         { 289, "Link4 Corporation" },
4140         { 290, "Romutec Steuer-u. Regelsysteme GmbH" },
4141         { 291, "Pribusin, Inc." },
4142         { 292, "Advantage Controls" },
4143         { 293, "Critical Room Control" },
4144         { 294, "LEGRAND" },
4145         { 295, "Tongdy Control Technology Co., Ltd." },
4146         { 296, "ISSARO Integrierte Systemtechnik" },
4147         { 297, "Pro-Dev Industries" },
4148         { 298, "DRI-STEEM" },
4149         { 299, "Creative Electronic GmbH" },
4150         { 300, "Swegon AB" },
4151         { 301, "Jan Brachacek" },
4152         { 302, "Hitachi Appliances, Inc." },
4153         { 303, "Real Time Automation, Inc." },
4154         { 304, "ITEC Hankyu-Hanshin Co." },
4155         { 305, "Cyrus E&M Engineering Co., Ltd." },
4156         { 306, "Racine Federated, Inc." },
4157         { 307, "Verari Systems, Inc." },
4158         { 308, "Elesta GmbH Building Automation" },
4159         { 309, "Securiton" },
4160         { 310, "OSlsoft, Inc." },
4161         { 311, "Hanazeder Electronic GmbH" },
4162         { 312, "Honeywell Security Deutschland, Novar GmbH" },
4163         { 313, "Siemens Energy & Automation, Inc." },
4164         { 314, "ETM Professional Control GmbH" },
4165         { 315, "Meitav-tec, Ltd." },
4166         { 316, "Janitza Electronics GmbH" },
4167         { 317, "MKS Nordhausen" },
4168         { 318, "De Gier Drive Systems B.V." },
4169         { 319, "Cypress Envirosystems" },
4170         { 320, "SMARTron s.r.o." },
4171         { 321, "Verari Systems, Inc." },
4172         { 322, "K-W Electronic Service, Inc." },
4173         { 323, "ALFA-SMART Energy Management" },
4174         { 324, "Telkonet, Inc." },
4175         { 325, "Securiton GmbH" },
4176         { 326, "Cemtrex, Inc." },
4177         { 327, "Performance Technologies, Inc." },
4178         { 328, "Xtralis (Aust) Pty Ltd" },
4179         { 329, "TROX GmbH" },
4180         { 330, "Beijing Hysine Technology Co., Ltd" },
4181         { 331, "RCK Controls, Inc." },
4182         { 332, "ACELIA" },
4183         { 333, "Novar/Honeywell" },
4184         { 334, "The S4 Group, Inc." },
4185         { 335, "Schneider Electric" },
4186         { 336, "LHA Systems" },
4187         { 337, "GHM engineering Group, Inc." },
4188         { 338, "Cllimalux S.A." },
4189         { 339, "VAISALA Oyj" },
4190         { 340, "COMPLEX (Beijing) Technology, Co., LTD." },
4191         { 342, "POWERPEG NSI Limited" },
4192         { 343, "BACnet Interoperability Testing Services, Inc." },
4193         { 344, "Teco a.s." },
4194         { 345, "Plexus Technology Limited"},
4195         { 346, "Energy Focus, Inc."},
4196         { 347, "Powersmiths International Corp."},
4197         { 348, "Nichibei Co., Ltd."},
4198         { 349, "HKC Technology Ltd."},
4199         { 350, "Ovation Networks, Inc."},
4200         { 351, "Setra Systems"},
4201         { 352, "AVG Automation"},
4202         { 353, "ZXC Ltd."},
4203         { 354, "Byte Sphere"},
4204         { 355, "Generiton Co., Ltd."},
4205         { 356, "Holter Regelarmaturen GmbH & Co. KG"},
4206         { 357, "Bedford Instruments, LLC"},
4207         { 358, "Standair Inc."},
4208         { 359, "WEG Automation - R&D"},
4209         { 360, "Prolon Control Systems ApS"},
4210         { 361, "Inneasoft"},
4211         { 362, "ConneXSoft GmbH"},
4212         { 363, "CEAG Notlichtsysteme GmbH"},
4213         { 364, "Distech Controls Inc."},
4214         { 365, "Industrial Technology Research Institute"},
4215         { 366, "ICONICS, Inc."},
4216         { 367, "IQ Controls s.c."},
4217         { 368, "OJ Electronics A/S"},
4218         { 369, "Rolbit Ltd."},
4219         { 370, "Synapsys Solutions Ltd."},
4220         { 371, "ACME Engineering Prod. Ltd."},
4221         { 372, "Zener Electric Pty, Ltd."},
4222         { 373, "Selectronix, Inc."},
4223         { 374, "Gorbet & Banerjee, LLC."},
4224         { 375, "IME"},
4225         { 376, "Stephen H. Dawson Computer Service"},
4226         { 377, "Accutrol, LLC"},
4227         { 378, "Schneider Elektronik GmbH"},
4228         { 379, "Alpha-Inno Tec GmbH"},
4229         { 380, "ADMMicro, Inc."},
4230         { 381, "Greystone Energy Systems, Inc."},
4231         { 382, "CAP Technologie"},
4232         { 383, "KeRo Systems"},
4233         { 384, "Domat Control System s.r.o."},
4234         { 385, "Efektronics Pty. Ltd."},
4235         { 386, "Hekatron Vertriebs GmbH"},
4236         { 387, "Securiton AG"},
4237         { 388, "Carlo Gavazzi Controls SpA"},
4238         { 389, "Chipkin Automation Systems"},
4239         { 390, "Savant Systems, LLC"},
4240         { 391, "Simmtronic Lighting Controls"},
4241         { 392, "Abelko Innovation AB"},
4242         { 393, "Seresco Technologies Inc."},
4243         { 394, "IT Watchdogs"},
4244         { 395, "Automation Assist Japan Corp."},
4245         { 396, "Thermokon Sensortechnik GmbH"},
4246         { 397, "EGauge Systems, LLC"},
4247         { 398, "Quantum Automation (ASIA) PTE, Ltd."},
4248         { 399, "Toshiba Lighting & Technology Corp."},
4249         { 400, "SPIN Engenharia de Automaca Ltda."},
4250         { 401, "Logistics Systems & Software Services India PVT. Ltd."},
4251         { 402, "Delta Controls Integration Products"},
4252         { 403, "Focus Media"},
4253         { 404, "LUMEnergi Inc."},
4254         { 405, "Kara Systems"},
4255         { 406, "RF Code, Inc."},
4256         { 407, "Fatek Automation Corp."},
4257         { 408, "JANDA Software Company, LLC"},
4258         { 409, "Open System Solutions Limited"},
4259         { 410, "Intelec Systems PTY Ltd."},
4260         { 411, "Ecolodgix, LLC"},
4261         { 412, "Douglas Lighting Controls"},
4262         { 413, "iSAtech GmbH intelligente Sensoren Aktoren technologie"},
4263         { 414, "AREAL"},
4264         { 415, "Beckhoff Automation GmbH"},
4265         { 416, "IPAS GmbH"},
4266         { 417, "KE2 Therm Solutions"},
4267         { 418, "Base2Products"},
4268         { 419, "DTL Controls, LLC"},
4269         { 420, "INNCOM International, Inc."},
4270         { 421, "BTR Netcom GmbH"},
4271         { 422, "Greentrol Automation, Inc"},
4272         { 423, "BELIMO Automation AG"},
4273         { 424, "Samsung Heavy Industries Co, Ltd"},
4274         { 425, "Triacta Power Technologies, Inc."},
4275         { 426, "Globestar Systems"},
4276         { 427, "MLB Advanced Media, LP"},
4277         { 428, "SWG Stuckmann Wirtschaftliche Gebaudesysteme GmbH"},
4278         { 429, "SensorSwitch"},
4279         { 430, "Multitek Power Limited"},
4280         { 431, "Aquametro AG"},
4281         { 432, "LG Electronics Inc."},
4282         { 433, "Electronic Theatre Controls, Inc."},
4283         { 434, "Mitsubishi Electric Corporation Nagoya Works"},
4284         { 435, "Delta Electronics, Inc."},
4285         { 436, "Elma Kurtalj, Ltd."},
4286         { 437, "ADT Fire and Security Sp. A.o.o."},
4287         { 438, "Nedap Security Management"},
4288         { 439, "ESC Automation Inc."},
4289         { 440, "DSP4YOU Ltd."},
4290         { 441, "GE Sensing and Inspection Technologies"},
4291         { 442, "Embedded Systems SIA"},
4292         { 443, "BEFEGA GmbH"},
4293         { 444, "Baseline Inc."},
4294         { 445, "M2M Systems Integrators"},
4295         { 446, "OEMCtrl"},
4296         { 447, "Clarkson Controls Limited"},
4297         { 448, "Rogerwell Control System Limited"},
4298         { 449, "SCL Elements"},
4299         { 450, "Hitachi Ltd."},
4300         { 451, "Newron System SA"},
4301         { 452, "BEVECO Gebouwautomatisering BV"},
4302         { 453, "Streamside Solutions"},
4303         { 454, "Yellowstone Soft"},
4304         { 455, "Oztech Intelligent Systems Pty Ltd."},
4305         { 456, "Novelan GmbH"},
4306         { 457, "Flexim Americas Corporation"},
4307         { 458, "ICP DAS Co., Ltd."},
4308         { 459, "CARMA Industries Inc."},
4309         { 460, "Log-One Ltd."},
4310         { 461, "TECO Electric & Machinery Co., Ltd."},
4311         { 462, "ConnectEx, Inc."},
4312         { 463, "Turbo DDC Sudwest"},
4313         { 464, "Quatrosense Environmental Ltd."},
4314         { 465, "Fifth Light Technology Ltd."},
4315         { 466, "Scientific Solutions, Ltd."},
4316         { 467, "Controller Area Network Solutions (M) Sdn Bhd"},
4317         { 468, "RESOL - Elektronische Regelungen GmbH"},
4318         { 469, "RPBUS LLC"},
4319         { 470, "BRS Sistemas Eletronicos"},
4320         { 471, "WindowMaster A/S"},
4321         { 472, "Sunlux Technologies Ltd."},
4322         { 473, "Measurlogic"},
4323         { 474, "Frimat GmbH"},
4324         { 475, "Spirax Sarco"},
4325         { 476, "Luxtron"},
4326         { 477, "Raypak Inc"},
4327         { 478, "Air Monitor Corporation"},
4328         { 479, "Regler Och Webbteknik Sverige (ROWS)"},
4329         { 480, "Intelligent Lighting Controls Inc."},
4330         { 481, "Sanyo Electric Industry Co., Ltd"},
4331         { 482, "E-Mon Energy Monitoring Products"},
4332         { 483, "Digital Control Systems"},
4333         { 484, "ATI Airtest Technologies, Inc."},
4334         { 485, "SCS SA"},
4335         { 486, "HMS Industrial Networks AB"},
4336         { 487, "Shenzhen Universal Intellisys Co Ltd"},
4337         { 488, "EK Intellisys Sdn Bhd"},
4338         { 489, "SysCom"},
4339         { 490, "Firecom, Inc."},
4340         { 491, "ESA Elektroschaltanlagen Grimma GmbH"},
4341         { 492, "Kumahira Co Ltd"},
4342         { 493, "Hotraco"},
4343         { 494, "SABO Elektronik GmbH"},
4344         { 495, "Equip'Trans"},
4345         { 496, "TCS Basys Controls"},
4346         { 497, "FlowCon International A/S"},
4347         { 498, "ThyssenKrupp Elevator Americas"},
4348         { 499, "Abatement Technologies"},
4349         { 500, "Continental Control Systems, LLC"},
4350         { 501, "WISAG Automatisierungstechnik GmbH & Co KG"},
4351         { 502, "EasyIO"},
4352         { 503, "EAP-Electric GmbH"},
4353         { 504, "Hardmeier"},
4354         { 505, "Mircom Group of Companies"},
4355         { 506, "Quest Controls"},
4356         { 507, "Mestek, Inc"},
4357         { 508, "Pulse Energy"},
4358         { 509, "Tachikawa Corporation"},
4359         { 510, "University of Nebraska-Lincoln"},
4360         { 511, "Redwood Systems"},
4361         { 512, "PASStec Industrie-Elektronik GmbH"},
4362         { 513, "NgEK, Inc."},
4363         { 514, "FAW Electronics Ltd"},
4364         { 515, "Jireh Energy Tech Co., Ltd."},
4365         { 516, "Enlighted Inc."},
4366         { 517, "El-Piast Sp. Z o.o"},
4367         { 518, "NetxAutomation Software GmbH"},
4368         { 519, "Invertek Drives"},
4369         { 520, "Deutschmann Automation GmbH & Co. KG"},
4370         { 521, "EMU Electronic AG"},
4371         { 522, "Phaedrus Limited"},
4372         { 523, "Sigmatek GmbH & Co KG"},
4373         { 524, "Marlin Controls"},
4374         { 525, "Circutor, SA"},
4375         { 526, "UTC Fire & Security"},
4376         { 527, "DENT Instruments, Inc."},
4377         { 528, "FHP Manufacturing Company - Bosch Group"},
4378         { 529, "GE Intelligent Platforms"},
4379         { 530, "Inner Range Pty Ltd"},
4380         { 531, "GLAS Energy Technology"},
4381         { 532, "MSR-Electronic-GmbH"},
4382         { 0, NULL }
4383 };
4384
4385 static int proto_bacapp = -1;
4386 static int hf_bacapp_type = -1;
4387 static int hf_bacapp_pduflags = -1;
4388 static int hf_bacapp_SEG = -1;
4389 static int hf_bacapp_MOR = -1;
4390 static int hf_bacapp_SA = -1;
4391 static int hf_bacapp_response_segments = -1;
4392 static int hf_bacapp_max_adpu_size = -1;
4393 static int hf_bacapp_invoke_id = -1;
4394 static int hf_bacapp_objectType = -1;
4395 static int hf_bacapp_instanceNumber = -1;
4396 static int hf_bacapp_sequence_number = -1;
4397 static int hf_bacapp_window_size = -1;
4398 static int hf_bacapp_service = -1;
4399 static int hf_bacapp_NAK = -1;
4400 static int hf_bacapp_SRV = -1;
4401 static int hf_Device_Instance_Range_Low_Limit = -1;
4402 static int hf_Device_Instance_Range_High_Limit = -1;
4403 static int hf_BACnetRejectReason = -1;
4404 static int hf_BACnetAbortReason = -1;
4405 static int hf_BACnetApplicationTagNumber = -1;
4406 static int hf_BACnetContextTagNumber = -1;
4407 static int hf_BACnetExtendedTagNumber = -1;
4408 static int hf_BACnetNamedTag = -1;
4409 static int hf_BACnetTagClass = -1;
4410 static int hf_BACnetCharacterSet = -1;
4411 static int hf_bacapp_tag_lvt = -1;
4412 static int hf_bacapp_tag_ProcessId = -1;
4413 static int hf_bacapp_uservice = -1;
4414 static int hf_BACnetPropertyIdentifier = -1;
4415 static int hf_BACnetVendorIdentifier = -1;
4416 static int hf_BACnetRestartReason = -1;
4417 static int hf_bacapp_tag_IPV4 = -1;
4418 static int hf_bacapp_tag_IPV6 = -1;
4419 static int hf_bacapp_tag_PORT = -1;
4420 /* some more variables for segmented messages */
4421 static int hf_msg_fragments = -1;
4422 static int hf_msg_fragment = -1;
4423 static int hf_msg_fragment_overlap = -1;
4424 static int hf_msg_fragment_overlap_conflicts = -1;
4425 static int hf_msg_fragment_multiple_tails = -1;
4426 static int hf_msg_fragment_too_long_fragment = -1;
4427 static int hf_msg_fragment_error = -1;
4428 static int hf_msg_fragment_count = -1;
4429 static int hf_msg_reassembled_in = -1;
4430 static int hf_msg_reassembled_length = -1;
4431
4432 static gint ett_msg_fragment = -1;
4433 static gint ett_msg_fragments = -1;
4434
4435 static gint ett_bacapp = -1;
4436 static gint ett_bacapp_control = -1;
4437 static gint ett_bacapp_tag = -1;
4438 static gint ett_bacapp_list = -1;
4439 static gint ett_bacapp_value = -1;
4440
4441 static dissector_handle_t data_handle;
4442 static gint32 propertyIdentifier = -1;
4443 static gint32 propertyArrayIndex = -1;
4444 static guint32 object_type = 4096;
4445
4446 static guint8 bacapp_flags = 0;
4447 static guint8 bacapp_seq = 0;
4448
4449 /* Defined to allow vendor identifier registration of private transfer dissectors */
4450 static dissector_table_t bacapp_dissector_table;
4451
4452
4453 /* Stat: BACnet Packets sorted by IP */
4454 bacapp_info_value_t bacinfo;
4455
4456 static const gchar* st_str_packets_by_ip = "BACnet Packets by IP";
4457 static const gchar* st_str_packets_by_ip_dst = "By Destination";
4458 static const gchar* st_str_packets_by_ip_src = "By Source";
4459 static int st_node_packets_by_ip = -1;
4460 static int st_node_packets_by_ip_dst = -1;
4461 static int st_node_packets_by_ip_src = -1;
4462
4463 static void
4464 bacapp_packet_stats_tree_init(stats_tree* st)
4465 {
4466         st_node_packets_by_ip = stats_tree_create_pivot(st, st_str_packets_by_ip, 0);
4467         st_node_packets_by_ip_src = stats_tree_create_node(st, st_str_packets_by_ip_src, st_node_packets_by_ip, TRUE);
4468         st_node_packets_by_ip_dst = stats_tree_create_node(st, st_str_packets_by_ip_dst, st_node_packets_by_ip, TRUE);
4469 }
4470
4471 static int
4472 bacapp_stats_tree_packet(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p)
4473 {
4474         int packets_for_this_dst;
4475         int packets_for_this_src;
4476         int service_for_this_dst;
4477         int service_for_this_src;
4478         int src_for_this_dst;
4479         int dst_for_this_src;
4480         int objectid_for_this_dst;
4481         int objectid_for_this_src;
4482         int instanceid_for_this_dst;
4483         int instanceid_for_this_src;
4484         gchar *dststr;
4485         gchar *srcstr;
4486         const bacapp_info_value_t *binfo = p;
4487
4488         srcstr = ep_strconcat("Src: ", address_to_str(&pinfo->src), NULL);
4489         dststr = ep_strconcat("Dst: ", address_to_str(&pinfo->dst), NULL);
4490
4491         tick_stat_node(st, st_str_packets_by_ip, 0, TRUE);
4492         packets_for_this_dst = tick_stat_node(st, st_str_packets_by_ip_dst, st_node_packets_by_ip, TRUE);
4493         packets_for_this_src = tick_stat_node(st, st_str_packets_by_ip_src, st_node_packets_by_ip, TRUE);
4494         src_for_this_dst = tick_stat_node(st, dststr, packets_for_this_dst, TRUE);
4495         dst_for_this_src = tick_stat_node(st, srcstr, packets_for_this_src, TRUE);
4496         service_for_this_src = tick_stat_node(st, dststr, dst_for_this_src, TRUE);
4497         service_for_this_dst = tick_stat_node(st, srcstr, src_for_this_dst, TRUE);
4498         if (binfo->service_type) {
4499                 objectid_for_this_dst = tick_stat_node(st, binfo->service_type, service_for_this_dst, TRUE);
4500                 objectid_for_this_src = tick_stat_node(st, binfo->service_type, service_for_this_src, TRUE);
4501                 if (binfo->object_ident) {
4502                         instanceid_for_this_dst=tick_stat_node(st, binfo->object_ident, objectid_for_this_dst, TRUE);
4503                         tick_stat_node(st, binfo->instance_ident, instanceid_for_this_dst, FALSE);
4504                         instanceid_for_this_src=tick_stat_node(st, binfo->object_ident, objectid_for_this_src, TRUE);
4505                         tick_stat_node(st, binfo->instance_ident, instanceid_for_this_src, FALSE);
4506                 }
4507         }
4508
4509         return 1;
4510 }
4511
4512 /* Stat: BACnet Packets sorted by Service */
4513 static const gchar* st_str_packets_by_service = "BACnet Packets by Service";
4514 static int st_node_packets_by_service = -1;
4515
4516 static void
4517 bacapp_service_stats_tree_init(stats_tree* st)
4518 {
4519         st_node_packets_by_service = stats_tree_create_pivot(st, st_str_packets_by_service, 0);
4520 }
4521
4522 static int
4523 bacapp_stats_tree_service(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p)
4524 {
4525         int servicetype;
4526         int src,dst;
4527         int objectid;
4528
4529         gchar *dststr;
4530         gchar *srcstr;
4531         const bacapp_info_value_t *binfo = p;
4532
4533         srcstr = ep_strconcat("Src: ", address_to_str(&pinfo->src), NULL);
4534         dststr = ep_strconcat("Dst: ", address_to_str(&pinfo->dst), NULL);
4535
4536         tick_stat_node(st, st_str_packets_by_service, 0, TRUE);
4537         if (binfo->service_type) {
4538                 servicetype = tick_stat_node(st, binfo->service_type, st_node_packets_by_service, TRUE);
4539                 src = tick_stat_node(st, srcstr, servicetype, TRUE);
4540                 dst = tick_stat_node(st, dststr, src, TRUE);
4541                 if (binfo->object_ident) {
4542                         objectid = tick_stat_node(st, binfo->object_ident, dst, TRUE);
4543                         tick_stat_node(st, binfo->instance_ident, objectid, FALSE);
4544                 }
4545         }
4546
4547         return 1;
4548 }
4549
4550 /* Stat: BACnet Packets sorted by Object Type */
4551 static const gchar* st_str_packets_by_objectid = "BACnet Packets by Object Type";
4552 static int st_node_packets_by_objectid = -1;
4553
4554 static void
4555 bacapp_objectid_stats_tree_init(stats_tree* st)
4556 {
4557         st_node_packets_by_objectid = stats_tree_create_pivot(st, st_str_packets_by_objectid, 0);
4558 }
4559
4560 static int
4561 bacapp_stats_tree_objectid(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p)
4562 {
4563         int servicetype;
4564         int src,dst;
4565         int objectid;
4566
4567         gchar *dststr;
4568         gchar *srcstr;
4569         const bacapp_info_value_t *binfo = p;
4570
4571         srcstr = ep_strconcat("Src: ", address_to_str(&pinfo->src), NULL);
4572         dststr = ep_strconcat("Dst: ", address_to_str(&pinfo->dst), NULL);
4573
4574         tick_stat_node(st, st_str_packets_by_objectid, 0, TRUE);
4575         if (binfo->object_ident) {
4576                 objectid = tick_stat_node(st, binfo->object_ident, st_node_packets_by_objectid, TRUE);
4577                 src = tick_stat_node(st, srcstr, objectid, TRUE);
4578                 dst = tick_stat_node(st, dststr, src, TRUE);
4579                 if (binfo->service_type) {
4580                         servicetype = tick_stat_node(st, binfo->service_type, dst, TRUE);
4581                         tick_stat_node(st, binfo->instance_ident, servicetype, FALSE);
4582                 }
4583         }
4584
4585         return 1;
4586 }
4587
4588 /* Stat: BACnet Packets sorted by Instance No */
4589 static const gchar* st_str_packets_by_instanceid = "BACnet Packets by Instance ID";
4590 static int st_node_packets_by_instanceid = -1;
4591
4592 static void
4593 bacapp_instanceid_stats_tree_init(stats_tree* st)
4594 {
4595         st_node_packets_by_instanceid = stats_tree_create_pivot(st, st_str_packets_by_instanceid, 0);
4596 }
4597
4598 static int
4599 bacapp_stats_tree_instanceid(stats_tree* st, packet_info* pinfo, epan_dissect_t* edt _U_, const void* p)
4600 {
4601         int servicetype;
4602         int src,dst;
4603         int instanceid;
4604
4605         gchar *dststr;
4606         gchar *srcstr;
4607         const bacapp_info_value_t *binfo = p;
4608
4609         srcstr = ep_strconcat("Src: ", address_to_str(&pinfo->src), NULL);
4610         dststr = ep_strconcat("Dst: ", address_to_str(&pinfo->dst), NULL);
4611
4612         tick_stat_node(st, st_str_packets_by_instanceid, 0, TRUE);
4613         if (binfo->object_ident) {
4614                 instanceid = tick_stat_node(st, binfo->instance_ident, st_node_packets_by_instanceid, TRUE);
4615                 src = tick_stat_node(st, srcstr, instanceid, TRUE);
4616                 dst = tick_stat_node(st, dststr, src, TRUE);
4617                 if (binfo->service_type) {
4618                         servicetype = tick_stat_node(st, binfo->service_type, dst, TRUE);
4619                         tick_stat_node(st, binfo->object_ident, servicetype, FALSE);
4620                 }
4621         }
4622         return 1;
4623 }
4624
4625
4626 /* register all BACnet Ststistic trees */
4627 static void
4628 register_bacapp_stat_trees(void)
4629 {
4630         stats_tree_register("bacapp","bacapp_ip","BACnet/Packets sorted by IP", 0,
4631                 bacapp_stats_tree_packet, bacapp_packet_stats_tree_init, NULL);
4632         stats_tree_register("bacapp","bacapp_service","BACnet/Packets sorted by Service", 0,
4633                 bacapp_stats_tree_service, bacapp_service_stats_tree_init, NULL);
4634         stats_tree_register("bacapp","bacapp_objectid","BACnet/Packets sorted by Object Type", 0,
4635                 bacapp_stats_tree_objectid, bacapp_objectid_stats_tree_init, NULL);
4636         stats_tree_register("bacapp","bacapp_instanceid","BACnet/Packets sorted by Instance ID", 0,
4637                 bacapp_stats_tree_instanceid, bacapp_instanceid_stats_tree_init, NULL);
4638 }
4639
4640 /* 'data' must be ep_ allocated */
4641 static gint
4642 updateBacnetInfoValue(gint whichval, gchar *data)
4643 {
4644         if (whichval == BACINFO_SERVICE) {
4645                 bacinfo.service_type = data;
4646                 return 0;
4647         }
4648         if (whichval == BACINFO_INVOKEID) {
4649                 bacinfo.invoke_id = data;
4650                 return 0;
4651         }
4652         if (whichval == BACINFO_OBJECTID) {
4653                 bacinfo.object_ident = data;
4654                 return 0;
4655         }
4656         if (whichval == BACINFO_INSTANCEID) {
4657                 bacinfo.instance_ident = data;
4658                 return 0;
4659         }
4660         return -1;
4661 }
4662
4663 static const fragment_items msg_frag_items = {
4664         /* Fragment subtrees */
4665         &ett_msg_fragment,
4666         &ett_msg_fragments,
4667         /* Fragment fields */
4668         &hf_msg_fragments,
4669         &hf_msg_fragment,
4670         &hf_msg_fragment_overlap,
4671         &hf_msg_fragment_overlap_conflicts,
4672         &hf_msg_fragment_multiple_tails,
4673         &hf_msg_fragment_too_long_fragment,
4674         &hf_msg_fragment_error,
4675         &hf_msg_fragment_count,
4676         /* Reassembled in field */
4677         &hf_msg_reassembled_in,
4678         /* Reassembled length field */
4679         &hf_msg_reassembled_length,
4680         /* Tag */
4681         "Message fragments"
4682 };
4683
4684 /* if BACnet uses the reserved values, then patch the corresponding values here, maximum 16 values are defined */
4685 static const guint MaxAPDUSize [] = { 50,128,206,480,1024,1476 };
4686
4687 #if 0
4688 /* FIXME: fGetMaxAPDUSize is commented out, as it is not used. It was used to set variables which were not later used. */
4689 static guint
4690 fGetMaxAPDUSize(guint8 idx)
4691 {
4692         /* only 16 values are defined, so use & 0x0f */
4693         /* check the size of the Array, deliver either the entry
4694            or the first entry if idx is outside of the array (bug 3736 comment#7) */
4695
4696         if ((idx & 0x0f) >= (gint)(sizeof(MaxAPDUSize)/sizeof(guint)))
4697                 return MaxAPDUSize[0];
4698         else
4699                 return MaxAPDUSize[idx & 0x0f];
4700 }
4701 #endif
4702
4703
4704 /* Used when there are ranges of reserved and proprietary enumerations */
4705 static const char*
4706 val_to_split_str(guint32 val, guint32 split_val, const value_string *vs,
4707         const char *fmt, const char *split_fmt)
4708 {
4709         if (val < split_val)
4710                 return val_to_str(val, vs, fmt);
4711         else
4712                 return val_to_str(val, vs, split_fmt);
4713 }
4714
4715 /* from clause 20.2.1.3.2 Constructed Data */
4716 /* returns true if the extended value is used */
4717 static gboolean
4718 tag_is_extended_value(guint8 tag)
4719 {
4720         return (tag & 0x07) == 5;
4721 }
4722
4723 static gboolean
4724 tag_is_opening(guint8 tag)
4725 {
4726         return (tag & 0x07) == 6;
4727 }
4728
4729 static gboolean
4730 tag_is_closing(guint8 tag)
4731 {
4732         return (tag & 0x07) == 7;
4733 }
4734
4735 /* from clause 20.2.1.1 Class
4736    class bit shall be one for context specific tags */
4737 /* returns true if the tag is context specific */
4738 static gboolean
4739 tag_is_context_specific(guint8 tag)
4740 {
4741         return (tag & 0x08) != 0;
4742 }
4743
4744 static gboolean
4745 tag_is_extended_tag_number(guint8 tag)
4746 {
4747         return ((tag & 0xF0) == 0xF0);
4748 }
4749
4750 static guint32
4751 object_id_type(guint32 object_identifier)
4752 {
4753         return ((object_identifier >> 22) & 0x3FF);
4754 }
4755
4756 static guint32
4757 object_id_instance(guint32 object_identifier)
4758 {
4759         return (object_identifier & 0x3FFFFF);
4760 }
4761
4762 static guint
4763 fTagNo (tvbuff_t *tvb, guint offset)
4764 {
4765         return (guint)(tvb_get_guint8(tvb, offset) >> 4);
4766 }
4767
4768 static gboolean
4769 fUnsigned32 (tvbuff_t *tvb, guint offset, guint32 lvt, guint32 *val)
4770 {
4771         gboolean valid = TRUE;
4772
4773         switch (lvt) {
4774                 case 1:
4775                         *val = tvb_get_guint8(tvb, offset);
4776                         break;
4777                 case 2:
4778                         *val = tvb_get_ntohs(tvb, offset);
4779                         break;
4780                 case 3:
4781                         *val = tvb_get_ntoh24(tvb, offset);
4782                         break;
4783                 case 4:
4784                         *val = tvb_get_ntohl(tvb, offset);
4785                         break;
4786                 default:
4787                         valid = FALSE;
4788                         break;
4789         }
4790
4791         return valid;
4792 }
4793
4794 static gboolean
4795 fUnsigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, guint64 *val)
4796 {
4797         gboolean valid = FALSE;
4798         gint64 value = 0;
4799         guint8 data, i;
4800
4801         if (lvt && (lvt <= 8)) {
4802                 valid = TRUE;
4803                 data = tvb_get_guint8(tvb, offset);
4804                 for (i = 0; i < lvt; i++) {
4805                         data = tvb_get_guint8(tvb, offset+i);
4806                         value = (value << 8) + data;
4807                 }
4808                 *val = value;
4809         }
4810
4811         return valid;
4812 }
4813
4814 /* BACnet Signed Value uses 2's complement notation, but with a twist:
4815    All signed integers shall be encoded in the smallest number of octets
4816    possible.  That is, the first octet of any multi-octet encoded value
4817    shall not be X'00' if the most significant bit (bit 7) of the second
4818    octet is 0, and the first octet shall not be X'FF' if the most
4819    significant bit of the second octet is 1. ASHRAE-135-2004-20.2.5 */
4820 static gboolean
4821 fSigned64 (tvbuff_t *tvb, guint offset, guint32 lvt, gint64 *val)
4822 {
4823         gboolean valid = FALSE;
4824         gint64 value = 0;
4825         guint8 data;
4826         guint32 i;
4827
4828         /* we can only handle 7 bytes for a 64-bit value due to signed-ness */
4829         if (lvt && (lvt <= 7)) {
4830                 valid = TRUE;
4831                 data = tvb_get_guint8(tvb, offset);
4832                 if ((data & 0x80) != 0)
4833                         value = (-1 << 8) | data;
4834                 else
4835                         value = data;
4836                 for (i = 1; i < lvt; i++) {
4837                         data = tvb_get_guint8(tvb, offset+i);
4838                         value = (value << 8) + data;
4839                 }
4840                 *val = value;
4841         }
4842
4843         return valid;
4844 }
4845
4846 static guint
4847 fTagHeaderTree (tvbuff_t *tvb, proto_tree *tree, guint offset,
4848         guint8 *tag_no, guint8* tag_info, guint32 *lvt)
4849 {
4850         guint8 tag;
4851         guint8 value;
4852         guint tag_len = 1;
4853         guint lvt_len = 1; /* used for tree display of lvt */
4854         guint lvt_offset; /* used for tree display of lvt */
4855         proto_item *ti;
4856         proto_tree *subtree;
4857
4858         lvt_offset = offset;
4859         tag = tvb_get_guint8(tvb, offset);
4860         *tag_info = 0;
4861         *lvt = tag & 0x07;
4862         /* To solve the problem of lvt values of 6/7 being indeterminate - it */
4863         /* can mean open/close tag or length of 6/7 after the length is */
4864         /* computed below - store whole tag info, not just context bit. */
4865         if (tag_is_context_specific(tag)) *tag_info = tag & 0x0F;
4866         *tag_no = tag >> 4;
4867         if (tag_is_extended_tag_number(tag)) {
4868                 *tag_no = tvb_get_guint8(tvb, offset + tag_len++);
4869         }
4870         if (tag_is_extended_value(tag)) {       /* length is more than 4 Bytes */
4871                 lvt_offset += tag_len;
4872                 value = tvb_get_guint8(tvb, lvt_offset);
4873                 tag_len++;
4874                 if (value == 254) { /* length is encoded with 16 Bits */
4875                         *lvt = tvb_get_ntohs(tvb, lvt_offset+1);
4876                         tag_len += 2;
4877                         lvt_len += 2;
4878                 } else if (value == 255) { /* length is encoded with 32 Bits */
4879                         *lvt = tvb_get_ntohl(tvb, lvt_offset+1);
4880                         tag_len += 4;
4881                         lvt_len += 4;
4882                 } else
4883                         *lvt = value;
4884         }
4885
4886         if (tree) {
4887                 if (tag_is_opening(tag))
4888                         ti = proto_tree_add_text(tree, tvb, offset, tag_len, "{[%u]", *tag_no );
4889                 else if (tag_is_closing(tag))
4890                         ti = proto_tree_add_text(tree, tvb, offset, tag_len, "}[%u]", *tag_no );
4891                 else if (tag_is_context_specific(tag)) {
4892                         ti = proto_tree_add_text(tree, tvb, offset, tag_len,
4893                                 "Context Tag: %u, Length/Value/Type: %u",
4894                                 *tag_no, *lvt);
4895                 } else
4896                         ti = proto_tree_add_text(tree, tvb, offset, tag_len,
4897                                 "Application Tag: %s, Length/Value/Type: %u",
4898                                 val_to_str(*tag_no,
4899                                         BACnetApplicationTagNumber,
4900                                         ASHRAE_Reserved_Fmt),
4901                                         *lvt);
4902
4903                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
4904                 /* details if needed */
4905                 proto_tree_add_item(subtree, hf_BACnetTagClass, tvb, offset, 1, ENC_BIG_ENDIAN);
4906                 if (tag_is_extended_tag_number(tag)) {
4907                         proto_tree_add_uint_format(subtree,
4908                                         hf_BACnetContextTagNumber,
4909                                         tvb, offset, 1, tag,
4910                                         "Extended Tag Number");
4911                         proto_tree_add_item(subtree,
4912                                 hf_BACnetExtendedTagNumber,
4913                                 tvb, offset + 1, 1, ENC_BIG_ENDIAN);
4914                 } else {
4915                         if (tag_is_context_specific(tag))
4916                                 proto_tree_add_item(subtree,
4917                                         hf_BACnetContextTagNumber,
4918                                         tvb, offset, 1, ENC_BIG_ENDIAN);
4919                         else
4920                                 proto_tree_add_item(subtree,
4921                                         hf_BACnetApplicationTagNumber,
4922                                         tvb, offset, 1, ENC_BIG_ENDIAN);
4923                 }
4924                 if (tag_is_closing(tag) || tag_is_opening(tag))
4925                         proto_tree_add_item(subtree,
4926                                 hf_BACnetNamedTag,
4927                                 tvb, offset, 1, ENC_BIG_ENDIAN);
4928                 else if (tag_is_extended_value(tag)) {
4929                         proto_tree_add_item(subtree,
4930                                 hf_BACnetNamedTag,
4931                                 tvb, offset, 1, ENC_BIG_ENDIAN);
4932                         proto_tree_add_uint(subtree, hf_bacapp_tag_lvt,
4933                                 tvb, lvt_offset, lvt_len, *lvt);
4934                 } else
4935                         proto_tree_add_uint(subtree, hf_bacapp_tag_lvt,
4936                                 tvb, lvt_offset, lvt_len, *lvt);
4937         }
4938
4939         return tag_len;
4940 }
4941
4942 static guint
4943 fTagHeader (tvbuff_t *tvb, guint offset, guint8 *tag_no, guint8* tag_info,
4944         guint32 *lvt)
4945 {
4946         return fTagHeaderTree (tvb, NULL, offset, tag_no, tag_info, lvt);
4947 }
4948
4949 static guint
4950 fNullTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
4951 {
4952         guint8 tag_no, tag_info;
4953         guint32 lvt;
4954         proto_item *ti;
4955         proto_tree *subtree;
4956
4957         ti = proto_tree_add_text(tree, tvb, offset, 1, "%sNULL", label);
4958         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
4959         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4960
4961         return offset + 1;
4962 }
4963
4964 static guint
4965 fBooleanTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
4966 {
4967         guint8 tag_no, tag_info;
4968         guint32 lvt = 0;
4969         proto_item *ti;
4970         proto_tree *subtree;
4971         guint bool_len = 1;
4972
4973         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4974         if (tag_info && lvt == 1) {
4975                 lvt = tvb_get_guint8(tvb, offset+1);
4976                 ++bool_len;
4977         }
4978
4979         ti = proto_tree_add_text(tree, tvb, offset, bool_len,
4980                 "%s%s", label, lvt == 0 ? "FALSE" : "TRUE");
4981         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
4982         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
4983
4984         return offset + bool_len;
4985 }
4986
4987 static guint
4988 fUnsignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
4989 {
4990         guint64 val = 0;
4991         guint8 tag_no, tag_info;
4992         guint32 lvt;
4993         guint tag_len;
4994         proto_item *ti;
4995         proto_tree *subtree;
4996
4997         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
4998         /* only support up to an 8 byte (64-bit) integer */
4999         if (fUnsigned64 (tvb, offset + tag_len, lvt, &val))
5000                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5001                         "%s(Unsigned) %" G_GINT64_MODIFIER "u", label, val);
5002         else
5003                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5004                         "%s - %u octets (Unsigned)", label, lvt);
5005         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5006         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5007
5008         return offset+tag_len+lvt;
5009 }
5010
5011 static guint
5012 fDevice_Instance (tvbuff_t *tvb, proto_tree *tree, guint offset, int hf)
5013 {
5014         guint8 tag_no, tag_info;
5015         guint32 lvt;
5016         guint tag_len;
5017         proto_item *ti;
5018         proto_tree *subtree;
5019
5020         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5021         ti = proto_tree_add_item(tree, hf, tvb, offset+tag_len, lvt, ENC_BIG_ENDIAN);
5022         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5023         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5024
5025         return offset+tag_len+lvt;
5026 }
5027
5028 /* set split_val to zero when not needed */
5029 static guint
5030 fEnumeratedTagSplit (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
5031         const value_string *vs, guint32 split_val)
5032 {
5033         guint32 val = 0;
5034         guint8 tag_no, tag_info;
5035         guint32 lvt;
5036         guint tag_len;
5037         proto_item *ti;
5038         proto_tree *subtree;
5039
5040         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5041         /* only support up to a 4 byte (32-bit) enumeration */
5042         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val)) {
5043                 if (vs)
5044                         ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5045                                 "%s %s", label, val_to_split_str(val, split_val, vs,
5046                                 ASHRAE_Reserved_Fmt,Vendor_Proprietary_Fmt));
5047                 else
5048                         ti =proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5049                                 "%s %u", label, val);
5050         } else {
5051                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5052                         "%s - %u octets (enumeration)", label, lvt);
5053         }
5054         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5055         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5056
5057         return offset+tag_len+lvt;
5058 }
5059
5060 static guint
5061 fEnumeratedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
5062                 const value_string *vs)
5063 {
5064         return fEnumeratedTagSplit (tvb, tree, offset, label, vs, 0);
5065 }
5066
5067 static guint
5068 fSignedTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5069 {
5070         gint64 val = 0;
5071         guint8 tag_no, tag_info;
5072         guint32 lvt;
5073         guint tag_len;
5074         proto_item *ti;
5075         proto_tree *subtree;
5076
5077         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5078         if (fSigned64 (tvb, offset + tag_len, lvt, &val))
5079                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5080                         "%s(Signed) %" G_GINT64_MODIFIER "d", label, val);
5081         else
5082                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5083                         "%s - %u octets (Signed)", label, lvt);
5084         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5085         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5086
5087         return offset+tag_len+lvt;
5088 }
5089
5090 static guint
5091 fRealTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5092 {
5093         guint8 tag_no, tag_info;
5094         guint32 lvt;
5095         guint tag_len;
5096         gfloat f_val;
5097         proto_item *ti;
5098         proto_tree *subtree;
5099
5100         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
5101         f_val = tvb_get_ntohieee_float(tvb, offset+tag_len);
5102         ti = proto_tree_add_text(tree, tvb, offset, 4+tag_len,
5103                 "%s%f (Real)", label, f_val);
5104         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5105         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5106
5107         return offset+tag_len+4;
5108 }
5109
5110 static guint
5111 fDoubleTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5112 {
5113         guint8 tag_no, tag_info;
5114         guint32 lvt;
5115         guint tag_len;
5116         gdouble d_val;
5117         proto_item *ti;
5118         proto_tree *subtree;
5119
5120         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
5121         d_val = tvb_get_ntohieee_double(tvb, offset+tag_len);
5122         ti = proto_tree_add_text(tree, tvb, offset, 8+tag_len,
5123                 "%s%f (Double)", label, d_val);
5124         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5125         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5126
5127         return offset+tag_len+8;
5128 }
5129
5130 static guint
5131 fProcessId (tvbuff_t *tvb, proto_tree *tree, guint offset)
5132 {
5133         guint32 val = 0, lvt;
5134         guint8 tag_no, tag_info;
5135         proto_item *ti;
5136         proto_tree *subtree;
5137         guint tag_len;
5138
5139         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5140         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val))
5141                 ti = proto_tree_add_uint(tree, hf_bacapp_tag_ProcessId,
5142                         tvb, offset, lvt+tag_len, val);
5143         else
5144                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5145                         "Process Identifier - %u octets (Signed)", lvt);
5146         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5147         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5148         offset += tag_len + lvt;
5149
5150         return offset;
5151 }
5152
5153 static guint
5154 fTimeSpan (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5155 {
5156         guint32 val = 0, lvt;
5157         guint8 tag_no, tag_info;
5158         proto_item *ti;
5159         proto_tree *subtree;
5160         guint tag_len;
5161
5162         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5163         if (fUnsigned32 (tvb, offset+tag_len, lvt, &val))
5164                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5165                 "%s (hh.mm.ss): %d.%02d.%02d%s",
5166                 label,
5167                 (val / 3600), ((val % 3600) / 60), (val % 60),
5168                 val == 0 ? " (indefinite)" : "");
5169         else
5170                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5171                         "%s - %u octets (Signed)", label, lvt);
5172         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5173         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5174
5175         return offset+tag_len+lvt;
5176 }
5177
5178 static guint
5179 fWeekNDay (tvbuff_t *tvb, proto_tree *tree, guint offset)
5180 {
5181         guint32 month, weekOfMonth, dayOfWeek;
5182         guint8 tag_no, tag_info;
5183         guint32 lvt;
5184         guint tag_len;
5185         proto_item *ti;
5186         proto_tree *subtree;
5187
5188         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5189         month = tvb_get_guint8(tvb, offset+tag_len);
5190         weekOfMonth = tvb_get_guint8(tvb, offset+tag_len+1);
5191         dayOfWeek = tvb_get_guint8(tvb, offset+tag_len+2);
5192         ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s %s, %s",
5193                                  val_to_str(month, months, "month (%d) not found"),
5194                                  val_to_str(weekOfMonth, weekofmonth, "week of month (%d) not found"),
5195                                  val_to_str(dayOfWeek, day_of_week, "day of week (%d) not found"));
5196         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5197         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5198
5199         return offset+tag_len+lvt;
5200 }
5201
5202 static guint
5203 fDate (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5204 {
5205         guint32 year, month, day, weekday;
5206         guint8 tag_no, tag_info;
5207         guint32 lvt;
5208         guint tag_len;
5209         proto_item *ti;
5210         proto_tree *subtree;
5211
5212         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5213         year = tvb_get_guint8(tvb, offset+tag_len);
5214         month = tvb_get_guint8(tvb, offset+tag_len+1);
5215         day = tvb_get_guint8(tvb, offset+tag_len+2);
5216         weekday = tvb_get_guint8(tvb, offset+tag_len+3);
5217         if ((year == 255) && (day == 255) && (month == 255) && (weekday == 255)) {
5218                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5219                         "%sany", label);
5220         }
5221         else if (year != 255) {
5222                 year += 1900;
5223                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5224                         "%s%s %d, %d, (Day of Week = %s)",
5225                         label, val_to_str(month,
5226                                 months,
5227                                 "month (%d) not found"),
5228                         day, year, val_to_str(weekday,
5229                                 day_of_week,
5230                                 "(%d) not found"));
5231         } else {
5232                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5233                         "%s%s %d, any year, (Day of Week = %s)",
5234                         label, val_to_str(month, months, "month (%d) not found"),
5235                         day, val_to_str(weekday, day_of_week, "(%d) not found"));
5236         }
5237         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5238         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5239
5240         return offset+tag_len+lvt;
5241 }
5242
5243 static guint
5244 fTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5245 {
5246         guint32 hour, minute, second, msec, lvt;
5247         guint8 tag_no, tag_info;
5248         guint tag_len;
5249         proto_item *ti;
5250         proto_tree *subtree;
5251
5252         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5253         hour = tvb_get_guint8(tvb, offset+tag_len);
5254         minute = tvb_get_guint8(tvb, offset+tag_len+1);
5255         second = tvb_get_guint8(tvb, offset+tag_len+2);
5256         msec = tvb_get_guint8(tvb, offset+tag_len+3);
5257         if ((hour == 255) && (minute == 255) && (second == 255) && (msec == 255))
5258                 ti = proto_tree_add_text(tree, tvb, offset,
5259                         lvt+tag_len, "%sany", label);
5260         else
5261                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5262                         "%s%d:%02d:%02d.%d %s = %02d:%02d:%02d.%d",
5263                         label,
5264                         hour > 12 ? hour - 12 : hour,
5265                         minute, second, msec,
5266                         hour >= 12 ? "P.M." : "A.M.",
5267                         hour, minute, second, msec);
5268         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5269         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5270
5271         return offset+tag_len+lvt;
5272 }
5273
5274 static guint
5275 fDateTime (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5276 {
5277         proto_tree *subtree = tree;
5278         proto_item *tt;
5279
5280         if (label != NULL) {
5281                 tt = proto_tree_add_text (subtree, tvb, offset, 10, "%s", label);
5282                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
5283         }
5284         offset = fDate (tvb,subtree,offset,"Date: ");
5285         return fTime (tvb,subtree,offset,"Time: ");
5286 }
5287
5288 static guint
5289 fTimeValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5290 {
5291         guint lastoffset = 0;
5292         guint8 tag_no, tag_info;
5293         guint32 lvt;
5294
5295         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
5296                 lastoffset = offset;
5297                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5298                 if (tag_is_closing(tag_info)) {   /* closing Tag, but not for me */
5299                         return offset;
5300                 }
5301                 offset = fTime    (tvb,tree,offset,"Time: ");
5302                 offset = fApplicationTypes(tvb, pinfo, tree, offset, "Value: ");
5303
5304                 if (offset==lastoffset) break;    /* exit loop if nothing happens inside */
5305         }
5306         return offset;
5307 }
5308
5309 static guint
5310 fCalendarEntry (tvbuff_t *tvb, proto_tree *tree, guint offset)
5311 {
5312         guint8 tag_no, tag_info;
5313         guint32 lvt;
5314
5315         switch (fTagNo(tvb, offset)) {
5316         case 0: /* Date */
5317                 offset = fDate    (tvb, tree, offset, "Date: ");
5318                 break;
5319         case 1: /* dateRange */
5320                 offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
5321                 offset = fDateRange (tvb, tree, offset);
5322                 offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
5323                 break;
5324         case 2: /* BACnetWeekNDay */
5325                 offset = fWeekNDay (tvb, tree, offset);
5326                 break;
5327         default:
5328                 return offset;
5329         }
5330
5331         return offset;
5332 }
5333
5334 static guint
5335 fEventTimeStamps( tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset)
5336 {
5337         guint32 lvt = 0;
5338         proto_tree* subtree = tree;
5339         proto_item* ti = 0;
5340
5341         if (tvb_reported_length_remaining(tvb, offset) > 0) {
5342                 ti = proto_tree_add_text(tree, tvb, offset, lvt, "eventTimeStamps");
5343                 if (ti) {
5344                         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5345                 }
5346                 offset = fTimeStamp (tvb, subtree, offset,"TO-OFFNORMAL timestamp: ");
5347                 offset = fTimeStamp (tvb, subtree, offset,"TO-FAULT timestamp: ");
5348                 offset = fTimeStamp (tvb, subtree, offset,"TO-NORMAL timestamp: ");
5349         }
5350         return offset;
5351 }
5352
5353 static guint
5354 fTimeStamp (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5355 {
5356         guint8 tag_no = 0, tag_info = 0;
5357         guint32 lvt = 0;
5358
5359         if (tvb_reported_length_remaining(tvb, offset) > 0) {   /* don't loop, it's a CHOICE */
5360                 switch (fTagNo(tvb, offset)) {
5361                 case 0: /* time */
5362                         offset = fTime (tvb, tree, offset, label?label:"time: ");
5363                         break;
5364                 case 1: /* sequenceNumber */
5365                         offset = fUnsignedTag (tvb, tree, offset,
5366                                 label?label:"sequence number: ");
5367                         break;
5368                 case 2: /* dateTime */
5369                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
5370                         offset = fDateTime (tvb, tree, offset, label?label:"date time: ");
5371                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
5372                         break;
5373                 default:
5374                         return offset;
5375                 }
5376         }
5377
5378         return offset;
5379 }
5380
5381
5382 static guint
5383 fClientCOV (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5384 {
5385         if (tvb_reported_length_remaining(tvb, offset) > 0) {
5386                 offset = fApplicationTypes(tvb,pinfo,tree,offset, "increment: ");
5387         }
5388         return offset;
5389 }
5390
5391 static const value_string
5392 BACnetDaysOfWeek [] = {
5393         {0,"Monday" },
5394         {1,"Tuesday" },
5395         {2,"Wednesday" },
5396         {3,"Thursday" },
5397         {4,"Friday" },
5398         {5,"Saturday" },
5399         {6,"Sunday" },
5400         {0,NULL }
5401 };
5402
5403 static guint
5404 fDestination (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5405 {
5406         if (tvb_reported_length_remaining(tvb, offset) > 0) {
5407                 offset = fApplicationTypesEnumerated(tvb,pinfo,tree,offset,
5408                         "valid Days: ", BACnetDaysOfWeek);
5409                 offset = fTime (tvb,tree,offset,"from time: ");
5410                 offset = fTime (tvb,tree,offset,"to time: ");
5411                 offset = fRecipient (tvb,pinfo,tree,offset);
5412                 offset = fProcessId (tvb,tree,offset);
5413                 offset = fApplicationTypes (tvb,pinfo,tree,offset,
5414                         "issue confirmed notifications: ");
5415                 offset = fBitStringTagVS (tvb,tree,offset,
5416                         "transitions: ", BACnetEventTransitionBits);
5417         }
5418         return offset;
5419 }
5420
5421
5422 static guint
5423 fOctetString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, guint32 lvt)
5424 {
5425         gchar *tmp;
5426         guint start = offset;
5427         guint8 tag_no, tag_info;
5428         proto_tree* subtree = tree;
5429         proto_item* ti = 0;
5430
5431         offset += fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5432
5433         if (lvt > 0) {
5434                 tmp = tvb_bytes_to_str(tvb, offset, lvt);
5435                 ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s %s", label, tmp);
5436                 offset += lvt;
5437         }
5438
5439         if (ti)
5440                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5441
5442         fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt);
5443
5444         return offset;
5445 }
5446
5447 static guint
5448 fMacAddress (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label, guint32 lvt)
5449 {
5450         gchar *tmp;
5451         guint start = offset;
5452         guint8 tag_no, tag_info;
5453         proto_tree* subtree = tree;
5454         proto_item* ti = 0;
5455
5456         offset += fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5457
5458         ti = proto_tree_add_text(tree, tvb, offset, 6, "%s", label); /* just add the label, with the tagHeader information in its subtree */
5459
5460         if (lvt > 0) {
5461                 if (lvt == 6) { /* we have 6 Byte IP Address with 4 Octets IPv4 and 2 Octets Port Information */
5462
5463                         guint32 ip = tvb_get_ipv4(tvb, offset);
5464                         guint16 port =  tvb_get_ntohs(tvb, offset+4);
5465
5466                         proto_tree_add_ipv4(tree, hf_bacapp_tag_IPV4, tvb, offset, 4, ip);
5467                         proto_tree_add_uint(tree, hf_bacapp_tag_PORT, tvb, offset+4, 2, port);
5468
5469                 } else {
5470                         if (lvt == 18) { /* we have 18 Byte IP Address with 16 Octets IPv6 and 2 Octets Port Information */
5471                         struct e_in6_addr addr;
5472                         guint16 port =  tvb_get_ntohs(tvb, offset+16);
5473                         tvb_get_ipv6(tvb, offset, &addr);
5474
5475                         proto_tree_add_ipv6(tree, hf_bacapp_tag_IPV6, tvb, offset, 16, (const guint8 *) &addr);
5476                         proto_tree_add_uint(tree, hf_bacapp_tag_PORT, tvb, offset+16, 2, port);
5477
5478                         } else { /* we have 1 Byte MS/TP Address or anything else interpreted as an address */
5479                                 tmp = tvb_bytes_to_str(tvb, offset, lvt);
5480                                 ti = proto_tree_add_text(tree, tvb, offset, lvt, "%s", tmp);
5481                         }
5482                 }
5483                 offset += lvt;
5484         }
5485
5486         if (ti)
5487                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5488
5489         fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt);
5490
5491         return offset;
5492 }
5493
5494 static guint
5495 fAddress (tvbuff_t *tvb, proto_tree *tree, guint offset)
5496 {
5497         guint8 tag_no, tag_info;
5498         guint32 lvt;
5499         guint offs;
5500
5501         offset = fUnsignedTag (tvb, tree, offset, "network-number");
5502         offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5503         if (lvt == 0) {
5504                 proto_tree_add_text(tree, tvb, offset, offs, "MAC-address: broadcast");
5505                 offset += offs;
5506         } else
5507                 offset = fMacAddress (tvb, tree, offset, "MAC-address: ", lvt);
5508
5509         return offset;
5510 }
5511
5512 static guint
5513 fSessionKey (tvbuff_t *tvb, proto_tree *tree, guint offset)
5514 {
5515         offset = fOctetString (tvb,tree,offset,"session key: ", 8);
5516         return fAddress (tvb,tree,offset);
5517 }
5518
5519 static guint
5520 fObjectIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5521 {
5522         guint8  tag_no, tag_info;
5523         guint32 lvt;
5524         guint tag_length;
5525         proto_item *ti;
5526         proto_tree *subtree;
5527         guint32 object_id;
5528
5529         tag_length = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
5530         object_id = tvb_get_ntohl(tvb,offset+tag_length);
5531         object_type = object_id_type(object_id);
5532         ti = proto_tree_add_text(tree, tvb, offset, tag_length + 4,
5533                 "ObjectIdentifier: %s, %u",
5534                 val_to_split_str(object_type,
5535                         128,
5536                         BACnetObjectType,
5537                         ASHRAE_Reserved_Fmt,
5538                         Vendor_Proprietary_Fmt),
5539                 object_id_instance(object_id));
5540         if (col_get_writable(pinfo->cinfo))
5541                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s,%u ",
5542                         val_to_split_str(object_type,
5543                                 128,
5544                                 BACnetObjectType,
5545                                 ASHRAE_Reserved_Fmt,
5546                                 Vendor_Proprietary_Fmt),
5547                                 object_id_instance(object_id));
5548
5549         /* update BACnet Statistics */
5550         updateBacnetInfoValue(BACINFO_OBJECTID,
5551                               ep_strdup(val_to_split_str(object_type, 128,
5552                                         BACnetObjectType, ASHRAE_Reserved_Fmt,
5553                                         Vendor_Proprietary_Fmt)));
5554         updateBacnetInfoValue(BACINFO_INSTANCEID, ep_strdup_printf("Instance ID: %u",
5555                               object_id_instance(object_id)));
5556
5557         /* here are the details of how we arrived at the above text */
5558         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5559         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5560         offset += tag_length;
5561         proto_tree_add_item(subtree, hf_bacapp_objectType, tvb, offset, 4, ENC_BIG_ENDIAN);
5562         proto_tree_add_item(subtree, hf_bacapp_instanceNumber, tvb, offset, 4, ENC_BIG_ENDIAN);
5563         offset += 4;
5564
5565         return offset;
5566 }
5567
5568 static guint
5569 fRecipient (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5570 {
5571         guint8  tag_no, tag_info;
5572         guint32 lvt;
5573
5574         fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
5575         if (tag_no < 2) {
5576                 if (tag_no == 0) { /* device */
5577                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
5578                 }
5579                 else {  /* address */
5580                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
5581                         offset = fAddress (tvb, tree, offset);
5582                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
5583                 }
5584         }
5585         return offset;
5586 }
5587
5588 static guint
5589 fRecipientProcess (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5590 {
5591         guint lastoffset = 0;
5592         guint8  tag_no, tag_info;
5593         guint32 lvt;
5594         proto_tree* orgtree = tree;
5595         proto_item* tt;
5596         proto_tree* subtree;
5597
5598         /* beginning of new item - indent and label */
5599         tt = proto_tree_add_text(orgtree, tvb, offset, 1, "Recipient Process" );
5600         tree = proto_item_add_subtree(tt, ett_bacapp_value);
5601
5602         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
5603                 lastoffset = offset;
5604
5605                 switch (fTagNo(tvb, offset)) {
5606                 case 0: /* recipient */
5607                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt); /* show context open */
5608                         tt = proto_tree_add_text(tree, tvb, offset, 1, "Recipient");    /* add tree label and indent */
5609                         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
5610                         offset = fRecipient (tvb, pinfo, subtree, offset);
5611                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt); /* show context close */
5612                         break;
5613                 case 1: /* processId */
5614                         offset = fProcessId (tvb, tree, offset);
5615                         lastoffset = offset;
5616                         break;
5617                 default:
5618                         break;
5619                 }
5620                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
5621         }
5622         return offset;
5623 }
5624
5625 static guint
5626 fCOVSubscription (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5627 {
5628         guint lastoffset = 0;
5629         guint8  tag_no, tag_info;
5630         guint32 lvt;
5631         proto_tree* subtree;
5632         proto_item *tt;
5633         proto_tree* orgtree = tree;
5634         guint itemno = 1;
5635
5636         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
5637                 lastoffset = offset;
5638                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5639                 if (tag_is_closing(tag_info) ) {
5640                         return offset;
5641                 }
5642                 switch (tag_no) {
5643
5644                 case 0: /* recipient */
5645                                 /* beginning of new item in list */
5646                                 tt = proto_tree_add_text(orgtree, tvb, offset, 1, "Subscription %d",itemno);    /* add tree label and indent */
5647                                 itemno = itemno + 1;
5648                                 tree = proto_item_add_subtree(tt, ett_bacapp_value);
5649
5650                                 tt = proto_tree_add_text(tree, tvb, offset, 1, "Recipient");    /* add tree label and indent */
5651                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
5652                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt); /* show context open */
5653                                 offset = fRecipientProcess (tvb, pinfo, subtree, offset);
5654                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);      /* show context close */
5655                                 subtree = tree; /* done with this level - return to previous tree */
5656                         break;
5657                 case 1: /* MonitoredPropertyReference */
5658                                 tt = proto_tree_add_text(tree, tvb, offset, 1, "Monitored Property Reference");
5659                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
5660                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5661                                 offset = fBACnetObjectPropertyReference (tvb, pinfo, subtree, offset);
5662                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5663                                 subtree = tree;
5664                         break;
5665                 case 2: /* IssueConfirmedNotifications - boolean */
5666                         offset = fBooleanTag (tvb, tree, offset, "Issue Confirmed Notifications: ");
5667                         break;
5668                 case 3: /* TimeRemaining */
5669                         offset = fUnsignedTag (tvb, tree, offset, "Time Remaining: ");
5670                         break;
5671                 case 4: /* COVIncrement */
5672                         offset = fRealTag (tvb, tree, offset, "COV Increment: ");
5673                         break;
5674                 default:
5675                         break;
5676                 }
5677                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
5678         }
5679         return offset;
5680 }
5681
5682 static guint
5683 fAddressBinding (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5684 {
5685         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
5686         return fAddress (tvb, tree, offset);
5687 }
5688
5689 static guint
5690 fActionCommand (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tag_match)
5691 {
5692         guint lastoffset = 0, len;
5693         guint8 tag_no, tag_info;
5694         guint32 lvt;
5695         proto_tree *subtree = tree;
5696
5697         /* set the optional global properties to indicate not-used */
5698         propertyArrayIndex = -1;
5699         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
5700                 lastoffset = offset;
5701                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5702                 if (tag_is_closing(tag_info) ) {
5703                         if (tag_no == tag_match) {
5704                                 return offset;
5705                         }
5706                         offset += len;
5707                         subtree = tree;
5708                         continue;
5709                 }
5710                 switch (tag_no) {
5711
5712                 case 0: /* deviceIdentifier */
5713                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
5714                         break;
5715                 case 1: /* objectIdentifier */
5716                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
5717                         break;
5718                 case 2: /* propertyIdentifier */
5719                         offset = fPropertyIdentifier (tvb, pinfo, subtree, offset);
5720                         break;
5721                 case 3: /* propertyArrayIndex */
5722                         offset = fPropertyArrayIndex (tvb, subtree, offset);
5723                         break;
5724                 case 4: /* propertyValue */
5725                         offset = fPropertyValue (tvb, pinfo, subtree, offset, tag_info);
5726                         break;
5727                 case 5: /* priority */
5728                         offset = fUnsignedTag (tvb,subtree,offset,"Priority: ");
5729                         break;
5730                 case 6: /* postDelay */
5731                         offset = fUnsignedTag (tvb,subtree,offset,"Post Delay: ");
5732                         break;
5733                 case 7: /* quitOnFailure */
5734                         offset = fBooleanTag(tvb, subtree, offset,
5735                                 "Quit On Failure: ");
5736                         break;
5737                 case 8: /* writeSuccessful */
5738                         offset = fBooleanTag(tvb, subtree, offset,
5739                                 "Write Successful: ");
5740                         break;
5741                 default:
5742                         return offset;
5743                 }
5744                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
5745         }
5746         return offset;
5747 }
5748
5749 /* BACnetActionList ::= SEQUENCE{
5750       action [0] SEQUENCE OF BACnetActionCommand
5751       }
5752 */
5753 static guint
5754 fActionList (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5755 {
5756         guint lastoffset = 0, len;
5757         guint8 tag_no, tag_info;
5758         guint32 lvt;
5759         proto_tree *subtree = tree;
5760         proto_item *ti;
5761
5762         while (tvb_reported_length_remaining(tvb, offset)) {
5763                 lastoffset = offset;
5764                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5765                 if (tag_is_closing(tag_info)) {
5766                         subtree = tree;
5767                         if ( tag_no != 0 ) /* don't eat the closing property tag, just return */
5768                                 return offset;
5769                         offset += len;
5770                         continue;
5771                 }
5772                 if (tag_is_opening(tag_info)) {
5773                         ti = proto_tree_add_text(tree, tvb, offset, 1, "Action List");
5774                         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5775                         offset += fTagHeaderTree (tvb, subtree, offset,
5776                                 &tag_no, &tag_info, &lvt);
5777                 }
5778                 switch (tag_no) {
5779                         case 0: /* BACnetActionCommand */
5780                                 offset = fActionCommand (tvb, pinfo, subtree, offset, tag_no);
5781                                 break;
5782                         default:
5783                                 break;
5784                 }
5785                 if (offset == lastoffset) break;    /* nothing happened, exit loop */
5786         }
5787         return offset;
5788 }
5789
5790 static guint
5791 fPropertyIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
5792 {
5793         guint8 tag_no, tag_info;
5794         guint32 lvt;
5795         guint tag_len;
5796         proto_item *ti;
5797         proto_tree *subtree;
5798         const gchar *label = "Property Identifier";
5799
5800         propertyIdentifier = 0; /* global Variable */
5801         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5802         /* can we decode this value? */
5803         if (fUnsigned32 (tvb, offset+tag_len, lvt, (guint32 *)&propertyIdentifier)) {
5804                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5805                         "%s: %s (%u)", label,
5806                         val_to_split_str(propertyIdentifier, 512,
5807                                 BACnetPropertyIdentifier,
5808                                 ASHRAE_Reserved_Fmt,
5809                                 Vendor_Proprietary_Fmt), propertyIdentifier);
5810                 if (col_get_writable(pinfo->cinfo))
5811                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
5812                                 val_to_split_str(propertyIdentifier, 512,
5813                                         BACnetPropertyIdentifier,
5814                                         ASHRAE_Reserved_Fmt,
5815                                         Vendor_Proprietary_Fmt));
5816         } else {
5817                 /* property identifiers cannot be larger than 22-bits */
5818                 return offset;
5819         }
5820         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5821         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5822         proto_tree_add_item(subtree, hf_BACnetPropertyIdentifier, tvb,
5823                 offset+tag_len, lvt, ENC_BIG_ENDIAN);
5824
5825         return offset+tag_len+lvt;
5826 }
5827
5828 static guint
5829 fPropertyArrayIndex (tvbuff_t *tvb, proto_tree *tree, guint offset)
5830 {
5831         guint8 tag_no, tag_info;
5832         guint32 lvt;
5833         guint tag_len;
5834         proto_item *ti;
5835         proto_tree *subtree;
5836
5837         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5838         if (fUnsigned32 (tvb, offset + tag_len, lvt, (guint32 *)&propertyArrayIndex))
5839                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5840                         "property Array Index (Unsigned) %u", propertyArrayIndex);
5841         else
5842                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
5843                         "property Array Index - %u octets (Unsigned)", lvt);
5844         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5845         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
5846
5847         return offset+tag_len+lvt;
5848 }
5849
5850 static guint
5851 fCharacterString (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
5852 {
5853         guint8 tag_no, tag_info, character_set;
5854         guint32 lvt, l;
5855         gsize inbytesleft, outbytesleft = 512;
5856         guint offs, extra = 1;
5857         guint8 *str_val;
5858         const char *coding;
5859         guint8 bf_arr[512], *out = &bf_arr[0];
5860         proto_item *ti;
5861         proto_tree *subtree;
5862         guint start = offset;
5863
5864         if (tvb_reported_length_remaining(tvb, offset) > 0) {
5865
5866                 offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5867
5868                 character_set = tvb_get_guint8(tvb, offset+offs);
5869                 /* Account for code page if DBCS */
5870                 if (character_set == 1) {
5871                     extra = 3;
5872                 }
5873                 offset += (offs+extra);
5874                 lvt -= (extra);
5875
5876                 do {
5877                         inbytesleft = l = MIN(lvt, 255);
5878                         /*
5879                          * XXX - are we guaranteed that these encoding
5880                          * names correspond, on *all* platforms with
5881                          * iconv(), to the encodings we want?
5882                          * If not (and perhaps even if so), we should
5883                          * perhaps have our own iconv() implementation,
5884                          * with a different name, so that we control the
5885                          * encodings it supports and the names of those
5886                          * encodings.
5887                          *
5888                          * We should also handle that in the general
5889                          * string handling code, rather than making it
5890                          * specific to the BACAPP dissector, as many
5891                          * other dissectors need to handle various
5892                          * character encodings.
5893                          */
5894                         str_val = tvb_get_ephemeral_string(tvb, offset, l);
5895                         /** this decoding may be not correct for multi-byte characters, Lka */
5896                         switch (character_set) {
5897                         case ANSI_X34:
5898                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UTF-8");
5899                                 coding = "UTF-8";
5900                                 break;
5901                         case IBM_MS_DBCS:
5902                                 out = str_val;
5903                                 coding = "IBM MS DBCS";
5904                                 break;
5905                         case JIS_C_6226:
5906                                 out = str_val;
5907                                 coding = "JIS C 6226";
5908                                 break;
5909                         case ISO_10646_UCS4:
5910                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-4BE");
5911                                 coding = "ISO 10646 UCS-4";
5912                                 break;
5913                         case ISO_10646_UCS2:
5914                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "UCS-2BE");
5915                                 coding = "ISO 10646 UCS-2";
5916                                 break;
5917                         case ISO_18859_1:
5918                                 fConvertXXXtoUTF8(str_val, &inbytesleft, out, &outbytesleft, "ISO8859-1");
5919                                 coding = "ISO 8859-1";
5920                                 break;
5921                         default:
5922                                 out = str_val;
5923                                 coding = "unknown";
5924                                 break;
5925                         }
5926                         ti = proto_tree_add_text(tree, tvb, offset, l, "%s%s '%s'", label, coding, out);
5927                         lvt-=l;
5928                         offset+=l;
5929                 } while (lvt > 0);
5930
5931                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5932
5933                 fTagHeaderTree (tvb, subtree, start, &tag_no, &tag_info, &lvt);
5934                 proto_tree_add_item(subtree, hf_BACnetCharacterSet, tvb, start+offs, 1, ENC_BIG_ENDIAN);
5935
5936                 if (character_set == 1) {
5937                     proto_tree_add_text(subtree, tvb, start+offs+1, 2, "Code Page: %d", tvb_get_ntohs(tvb, start+offs+1));
5938                 }
5939                 /* XXX - put the string value here */
5940         }
5941         return offset;
5942 }
5943
5944 static guint
5945 fBitStringTagVS (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label,
5946         const value_string *src)
5947 {
5948         guint8 tag_no, tag_info, tmp;
5949         gint j, unused, skip;
5950         guint start = offset;
5951         guint offs;
5952         guint32 lvt, i, numberOfBytes;
5953         guint8 bf_arr[256];
5954         proto_tree* subtree = tree;
5955         proto_item* ti = 0;
5956
5957         offs = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
5958         numberOfBytes = lvt-1; /* Ignore byte for unused bit count */
5959         offset+=offs;
5960         unused = tvb_get_guint8(tvb, offset); /* get the unused Bits */
5961         ti = proto_tree_add_text(tree, tvb, start, offs+lvt,
5962                                 "%s(Bit String)",
5963                                 label);
5964         if (ti) {
5965                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
5966         }
5967         fTagHeaderTree(tvb, subtree, start, &tag_no, &tag_info, &lvt);
5968         proto_tree_add_text(subtree, tvb, offset, 1,
5969                                 "Unused bits: %u",
5970                                 unused);
5971         skip = 0;
5972         for (i = 0; i < numberOfBytes; i++) {
5973                 tmp = tvb_get_guint8(tvb, (offset)+i+1);
5974                 if (i == numberOfBytes-1) { skip = unused; }
5975                 for (j = 0; j < 8-skip; j++) {
5976                         if (src != NULL) {
5977                                 if (tmp & (1 << (7 - j)))
5978                                         proto_tree_add_text(subtree, tvb,
5979                                                 offset+i+1, 1,
5980                                                 "%s = TRUE",
5981                                                 val_to_str((guint) (i*8 +j),
5982                                                         src,
5983                                                         ASHRAE_Reserved_Fmt));
5984                                 else
5985                                         proto_tree_add_text(subtree, tvb,
5986                                                 offset+i+1, 1,
5987                                                 "%s = FALSE",
5988                                                 val_to_str((guint) (i*8 +j),
5989                                                         src,
5990                                                         ASHRAE_Reserved_Fmt));
5991                         } else {
5992                                 bf_arr[MIN(255,(i*8)+j)] = tmp & (1 << (7 - j)) ? '1' : '0';
5993                         }
5994                 }
5995         }
5996
5997         if (src == NULL) {
5998                 bf_arr[MIN(255,numberOfBytes*8-unused)] = 0;
5999                 proto_tree_add_text(subtree, tvb, offset, lvt, "B'%s'", bf_arr);
6000         }
6001
6002         offset+=lvt;
6003
6004         return offset;
6005 }
6006
6007 static guint
6008 fBitStringTag (tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
6009 {
6010         return fBitStringTagVS (tvb, tree, offset, label, NULL);
6011 }
6012
6013 /* handles generic application types, as well as enumerated and enumerations
6014    with reserved and proprietarty ranges (split) */
6015 static guint
6016 fApplicationTypesEnumeratedSplit (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset,
6017         const gchar *label, const value_string *src, guint32 split_val)
6018 {
6019         guint8 tag_no, tag_info;
6020         guint32 lvt;
6021         guint tag_len;
6022
6023         if (tvb_reported_length_remaining(tvb, offset) > 0) {
6024
6025                 tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6026                 if (!tag_is_context_specific(tag_info)) {
6027                         switch (tag_no) {
6028                                 case 0: /** NULL 20.2.2 */
6029                                         offset = fNullTag(tvb, tree, offset, label);
6030                                         break;
6031                                 case 1: /** BOOLEAN 20.2.3 */
6032                                         offset = fBooleanTag(tvb, tree, offset, label);
6033                                         break;
6034                                 case 2: /** Unsigned Integer 20.2.4 */
6035                                         offset = fUnsignedTag(tvb, tree, offset, label);
6036                                         break;
6037                                 case 3: /** Signed Integer 20.2.5 */
6038                                         offset = fSignedTag(tvb, tree, offset, label);
6039                                         break;
6040                                 case 4: /** Real 20.2.6 */
6041                                         offset = fRealTag(tvb, tree, offset, label);
6042                                         break;
6043                                 case 5: /** Double 20.2.7 */
6044                                         offset = fDoubleTag(tvb, tree, offset, label);
6045                                         break;
6046                                 case 6: /** Octet String 20.2.8 */
6047                                         offset = fOctetString (tvb, tree, offset, label, lvt);
6048                                         break;
6049                                 case 7: /** Character String 20.2.9 */
6050                                         offset = fCharacterString (tvb,tree,offset,label);
6051                                         break;
6052                                 case 8: /** Bit String 20.2.10 */
6053                                         offset = fBitStringTagVS (tvb, tree, offset, label, src);
6054                                         break;
6055                                 case 9: /** Enumerated 20.2.11 */
6056                                         offset = fEnumeratedTagSplit (tvb, tree, offset, label, src, split_val);
6057                                         break;
6058                                 case 10: /** Date 20.2.12 */
6059                                         offset = fDate (tvb, tree, offset, label);
6060                                         break;
6061                                 case 11: /** Time 20.2.13 */
6062                                         offset = fTime (tvb, tree, offset, label);
6063                                         break;
6064                                 case 12: /** BACnetObjectIdentifier 20.2.14 */
6065                                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
6066                                         break;
6067                                 case 13: /* reserved for ASHRAE */
6068                                 case 14:
6069                                 case 15:
6070                                         proto_tree_add_text(tree, tvb, offset, lvt+tag_len, "%s'reserved for ASHRAE'", label);
6071                                         offset+=lvt+tag_len;
6072                                         break;
6073                                 default:
6074                                         break;
6075                         }
6076
6077                 }
6078         }
6079         return offset;
6080 }
6081
6082 static guint
6083 fShedLevel (tvbuff_t *tvb, proto_tree *tree, guint offset)
6084 {
6085         guint lastoffset = 0;
6086
6087         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6088                 lastoffset = offset;
6089
6090                 switch (fTagNo(tvb,offset)) {
6091                 case 0: /* percent */
6092                         offset = fUnsignedTag (tvb, tree, offset, "shed percent: ");
6093                         break;
6094                 case 1: /* level */
6095                         offset = fUnsignedTag (tvb, tree, offset, "shed level: ");
6096                         break;
6097                 case 2: /* amount */
6098                         offset = fRealTag(tvb, tree, offset, "shed amount: ");
6099                         break;
6100                 default:
6101                         return offset;
6102                 }
6103                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6104         }
6105         return offset;
6106 }
6107
6108 static guint
6109 fApplicationTypesEnumerated (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset,
6110         const gchar *label, const value_string *vs)
6111 {
6112         return fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, label, vs, 0);
6113 }
6114
6115 static guint
6116 fApplicationTypes (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset,
6117         const gchar *label)
6118 {
6119         return fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, label, NULL, 0);
6120 }
6121
6122 static guint
6123 fContextTaggedValue(tvbuff_t *tvb, proto_tree *tree, guint offset, const gchar *label)
6124 {
6125         guint8 tag_no, tag_info;
6126         guint32 lvt;
6127         guint tag_len;
6128         proto_item *ti;
6129         proto_tree *subtree;
6130         gint tvb_len;
6131
6132         (void)label;
6133         tag_len = fTagHeader(tvb, offset, &tag_no, &tag_info, &lvt);
6134         /* cap the the suggested length in case of bad data */
6135         tvb_len = tvb_reported_length_remaining(tvb, offset+tag_len);
6136         if ((tvb_len >= 0) && ((guint32)tvb_len < lvt)) {
6137                 lvt = tvb_len;
6138         }
6139         ti = proto_tree_add_text(tree, tvb, offset+tag_len, lvt,
6140                 "Context Value (as %u DATA octets)", lvt);
6141
6142         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
6143         fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
6144
6145         return offset + tag_len + lvt;
6146 }
6147 /*
6148 BACnetPrescale ::= SEQUENCE {   
6149         multiplier      [0] Unsigned,
6150 moduloDivide    [1] Unsigned
6151 }
6152 */
6153 static guint 
6154 fPrescale (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset)
6155 {
6156         guint8 tag_no, tag_info;
6157         guint32 lvt, len;
6158         guint lastoffset = 0;
6159
6160         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6161                 lastoffset = offset;
6162                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6163                 if (tag_is_closing(tag_info) ) {
6164                         return offset;
6165                         }
6166                 switch (tag_no) {
6167                 case 0: /* multiplier */
6168                         offset = fUnsignedTag (tvb,tree,offset,"Multiplier: ");
6169                         break;
6170                 case 1: /* moduloDivide */
6171                         offset = fUnsignedTag (tvb,tree,offset,"Modulo Divide: ");
6172                         break;
6173                 default:
6174                         return offset;
6175                 }
6176                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6177         }
6178         return offset;
6179
6180 }
6181 /*
6182 BACnetScale ::= CHOICE {
6183         floatScale      [0] REAL,
6184 integerScale    [1] INTEGER
6185 }
6186 */
6187 static guint 
6188 fScale (tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset)
6189 {
6190         guint8 tag_no, tag_info;
6191         guint32 lvt, len;
6192         guint lastoffset = 0;
6193
6194         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6195                 lastoffset = offset;
6196                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6197                 if (tag_is_closing(tag_info) ) {
6198                         return offset;
6199                         }
6200                 switch (tag_no) {
6201                 case 0: /* floatScale */
6202                         offset = fRealTag (tvb,tree,offset,"Float Scale: ");
6203                         break;
6204                 case 1: /* integerScale */
6205                         offset = fSignedTag (tvb,tree,offset,"Integer Scale: ");
6206                         break;
6207                 default:
6208                         return offset;
6209                 }
6210                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6211         }
6212         return offset;
6213 }
6214 /*
6215 BACnetAccumulatorRecord ::= SEQUENCE {
6216         timestamp               [0] BACnetDateTime,
6217         presentValue            [1] Unsigned,
6218         accumulatedValue        [2] Unsigned,
6219         accumulatortStatus      [3] ENUMERATED {
6220                                         normal                  (0),
6221                                         starting                (1),
6222                                         recovered               (2),
6223                                         abnormal                (3),
6224                                         failed                  (4)
6225                                         }
6226 }
6227 */
6228 static guint 
6229 fLoggingRecord (tvbuff_t *tvb, packet_info *pinfo  _U_, proto_tree *tree, guint offset)
6230 {
6231         guint8 tag_no, tag_info;
6232         guint32 lvt, len;
6233         guint lastoffset = 0;
6234
6235         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6236                 lastoffset = offset;
6237                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6238                 if (tag_is_closing(tag_info) ) {
6239                         return offset;
6240                         }
6241                 switch (tag_no) {
6242                 case 0: /* timestamp */
6243                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
6244                         offset = fDateTime (tvb, tree, offset, "Timestamp: ");
6245                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
6246                         break;
6247                 case 1: /* presentValue */
6248                         offset = fUnsignedTag (tvb,tree,offset,"Present Value: ");
6249                         break;
6250                 case 2: /* accumulatedValue */
6251                         offset = fUnsignedTag (tvb,tree,offset,"Accumulated Value: ");
6252                         break;
6253                 case 3: /* accumulatorStatus */
6254                         offset = fEnumeratedTag (tvb, tree, offset, "Accumulator Status: ", BACnetAccumulatorStatus);
6255                 default:
6256                         return offset;
6257                 }
6258                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6259         }
6260         return offset;
6261 }
6262
6263 /*
6264  SEQ OF Any enumeration (current usage is SEQ OF BACnetDoorAlarmState
6265 */
6266 static guint 
6267 fSequenceOfEnums (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label, const value_string *vs)
6268 {
6269         guint8 tag_no, tag_info;
6270         guint32 lvt, len;
6271         guint lastoffset = 0;
6272
6273         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6274                 lastoffset = offset;
6275                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6276                 if (tag_is_closing(tag_info) ) {
6277                         return offset;
6278                         }
6279                 offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, label, vs);
6280                 if ( offset == lastoffset ) break;
6281         }
6282         return offset;
6283 }
6284
6285 /*
6286 SEQ OF BACnetDeviceObjectReference (accessed as an array)
6287 }
6288 */
6289 static guint 
6290 fDoorMembers (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6291 {
6292         guint8 tag_no, tag_info;
6293         guint32 lvt, len;
6294         guint lastoffset = 0;
6295
6296         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6297                 lastoffset = offset;
6298                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6299                 if (tag_is_closing(tag_info) ) {
6300                         return offset;
6301                         }
6302                 offset = fDeviceObjectReference(tvb, pinfo, tree, offset);
6303                 if (offset == lastoffset) break;
6304         }
6305         return offset;
6306 }
6307
6308 /*
6309 SEQ OF ReadAccessSpecification
6310 */
6311 static guint 
6312 fListOfGroupMembers (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6313 {
6314         guint8 tag_no, tag_info;
6315         guint32 lvt, len;
6316         guint lastoffset = 0;
6317
6318         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6319                 lastoffset = offset;
6320                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6321                 if (tag_is_closing(tag_info) ) {
6322                         return offset;
6323                         }
6324                 offset = fReadAccessSpecification(tvb, pinfo, tree, offset);
6325                 if ( offset == lastoffset ) break;
6326         }
6327         return offset;
6328 }
6329
6330 static guint
6331 fAbstractSyntaxNType (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6332 {
6333         guint8 tag_no, tag_info;
6334         guint32 lvt;
6335         guint lastoffset = 0, depth = 0;
6336         char ar[256];
6337         guint32 save_object_type = object_type;
6338
6339         if (propertyIdentifier >= 0) {
6340                 g_snprintf (ar, sizeof(ar), "%s: ",
6341                         val_to_split_str(propertyIdentifier, 512,
6342                                 BACnetPropertyIdentifier,
6343                                 ASHRAE_Reserved_Fmt,
6344                                 Vendor_Proprietary_Fmt));
6345         } else {
6346                 g_snprintf (ar, sizeof(ar), "Abstract Type: ");
6347         }
6348         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6349                 lastoffset = offset;
6350                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6351                 if (tag_is_closing(tag_info)) { /* closing tag, but not for me */
6352                         if (depth <= 0) return offset;
6353                 }
6354
6355                 /* Application Tags */
6356                 switch (propertyIdentifier) {
6357                 case 2: /* action */
6358                         /* loop object is application tagged,
6359                                 command object is context tagged */
6360                         if (tag_is_context_specific(tag_info)) {
6361                                 /* BACnetActionList */
6362                                 offset = fActionList (tvb, pinfo, tree,offset);
6363                         } else {
6364                                 /* BACnetAction */
6365                                 offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar,
6366                                         BACnetAction);
6367                         }
6368                         break;
6369                 case 30: /* BACnetAddressBinding */
6370                         offset = fAddressBinding (tvb,pinfo,tree,offset);
6371                         break;
6372                 case 54: /* list of object property reference */
6373                         offset = fLOPR (tvb, pinfo, tree,offset);
6374                         break;
6375                 case 55: /* list-of-session-keys */
6376                         fSessionKey (tvb, tree, offset);
6377                         break;
6378                 case 79: /* object-type */
6379                 case 96: /* protocol-object-types-supported */
6380                         offset = fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset, ar,
6381                                 BACnetObjectType, 128);
6382                         break;
6383                 case 97: /* Protocol-Services-Supported */
6384                         offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar,
6385                                 BACnetServicesSupported);
6386                         break;
6387                 case 102: /* recipient-list */
6388                         offset = fDestination (tvb, pinfo, tree, offset);
6389                         break;
6390                 case 107: /* segmentation-supported */
6391                         offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar,
6392                                 BACnetSegmentation);
6393                         break;
6394                 case 111: /* Status-Flags */
6395                         offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar,
6396                                 BACnetStatusFlags);
6397                         break;
6398                 case 112: /* System-Status */
6399                         offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar,
6400                                 BACnetDeviceStatus);
6401                         break;
6402                 case 117: /* units */
6403                         offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset, ar,
6404                                 BACnetEngineeringUnits);
6405                         break;
6406                 case 87:        /* priority-array -- accessed as a BACnetARRAY */
6407                         if (propertyArrayIndex == 0) {
6408                                 /* BACnetARRAY index 0 refers to the length
6409                                 of the array, not the elements of the array */
6410                                 offset = fApplicationTypes (tvb, pinfo, tree, offset, ar);
6411                         } else {
6412                                 offset = fPriorityArray (tvb, pinfo, tree, offset);
6413                         }
6414                         break;
6415                 case 38:        /* exception-schedule */
6416                         if (object_type < 128) {
6417                                 if (propertyArrayIndex == 0) {
6418                                         /* BACnetARRAY index 0 refers to the length
6419                                         of the array, not the elements of the array */
6420                                         offset = fApplicationTypes (tvb, pinfo, tree, offset, ar);
6421                                 } else {
6422                                         offset = fSpecialEvent (tvb,pinfo,tree,offset);
6423                                 }
6424                         }
6425                         break;
6426                 case 19:  /* controlled-variable-reference */
6427                 case 60:  /* manipulated-variable-reference */
6428                 case 109: /* Setpoint-Reference */
6429                 case 132: /* log-device-object-property */
6430                         offset = fDeviceObjectPropertyReference (tvb, pinfo, tree, offset);
6431                         break;
6432                 case 123:       /* weekly-schedule -- accessed as a BACnetARRAY */
6433                         if (object_type < 128) {
6434                                 if (propertyArrayIndex == 0) {
6435                                         /* BACnetARRAY index 0 refers to the length
6436                                         of the array, not the elements of the array */
6437                                         offset = fApplicationTypes (tvb, pinfo, tree, offset, ar);
6438                                 } else {
6439                                         offset = fWeeklySchedule (tvb, pinfo, tree, offset);
6440                                 }
6441                         }
6442                         break;
6443                 case 127:       /* client COV increment */
6444                         offset = fClientCOV (tvb, pinfo, tree, offset);
6445                         break;
6446                 case 131:  /* log-buffer */
6447                         if ( object_type == 25 )
6448                                 offset = fEventLogRecord(tvb, pinfo, tree, offset);
6449                         else if ( object_type == 27 )
6450                                 offset = fLogMultipleRecord (tvb, pinfo, tree, offset);
6451                         else
6452                                 offset = fLogRecord (tvb, pinfo, tree, offset);
6453                         break;
6454                 case 159: /* member-of */
6455                 case 165: /* zone-members */
6456                         offset = fDeviceObjectReference (tvb, pinfo, tree, offset);
6457                         break;
6458                 case 196: /* last-restart-reason */
6459                         offset = fRestartReason (tvb, pinfo, tree, offset);
6460                         break;
6461                 case 212: /* actual-shed-level */
6462                 case 214: /* expected-shed-level */
6463                 case 218: /* requested-shed-level */
6464                         offset = fShedLevel (tvb, tree, offset);
6465                         break;
6466                 case 152: /* active-cov-subscriptions */
6467                         offset = fCOVSubscription (tvb, pinfo, tree, offset);
6468                         break;
6469                 case 23: /* date-list */
6470                         offset = fCalendarEntry(tvb, tree, offset);
6471                         break;
6472                 case 116: /* time-sychronization-recipients */
6473                         offset = fRecipient(tvb, pinfo, tree, offset);
6474                         break;
6475                 case 83: /* event-parameters */
6476                         offset = fEventParameter(tvb, pinfo, tree, offset);
6477                         break;
6478                 case 211: /* subordinate-list */
6479                         offset = fDeviceObjectReference (tvb, pinfo, tree, offset);
6480                         break;
6481                 case 130: /* event-time-stamp */
6482                         offset = fEventTimeStamps(tvb, pinfo, tree, offset);
6483                         break;
6484                 case 197: /* logging-type */
6485                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLoggingType);
6486                         break;
6487                 case 36: /* event-state */
6488                         offset = fApplicationTypesEnumeratedSplit(tvb, pinfo, tree, offset, ar, BACnetEventState, 64);
6489                         break;
6490                 case 103: /* reliability */
6491                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetReliability);
6492                         break;
6493                 case 72: /* notify-type */
6494                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetNotifyType);
6495                         break;
6496                 case 208: /* node-type */
6497                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetNodeType);
6498                         break;
6499                 case 231: /* door-status */
6500                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetDoorStatus);
6501                         break;
6502                 case 233: /* lock-status */
6503                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLockStatus);
6504                         break;
6505                 case 235: /* secured-status */
6506                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetDoorSecuredStatus);
6507                         break;
6508                 case 158: /* maintenance-required */
6509                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetMaintenance);
6510                         break;
6511                 case 92: /* program-state */
6512                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetProgramState);
6513                         break;
6514                 case 90: /* program-change */
6515                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetProgramRequest);
6516                         break;
6517                 case 100: /* reason-for-halt */
6518                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetProgramError);
6519                         break;
6520                 case 160: /* mode */
6521                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyMode);
6522                         break;
6523                 case 163: /* silenced */
6524                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetSilencedState);
6525                         break;
6526                 case 161: /* operation-expected */
6527                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyOperation);
6528                         break;
6529                 case 164: /* tracking-value */
6530                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetLifeSafetyState);
6531                         break;
6532                 case 41: /* file-access-method */
6533                         offset = fApplicationTypesEnumerated(tvb, pinfo, tree, offset, ar, BACnetFileAccessMethod);
6534                         break;
6535                 case 185:  /* prescale */
6536                         offset = fPrescale(tvb, pinfo, tree, offset);
6537                         break;
6538                 case 187:  /* scale */
6539                         offset = fScale(tvb, pinfo, tree, offset);
6540                         break;
6541                 case 184: /* logging-record */
6542                         offset = fLoggingRecord(tvb, pinfo, tree, offset);
6543                         break;
6544                 case 228: /* door-members */
6545                         offset = fDoorMembers(tvb, pinfo, tree, offset);
6546                         break;
6547                 case 181: /* input-reference */
6548                         offset = fObjectPropertyReference(tvb, pinfo, tree, offset);
6549                         break;
6550                 case 78: /* object-property-reference */
6551                         offset = fObjectPropertyReference(tvb, pinfo, tree, offset);
6552                         break;
6553                 case 234: /* masked-alarm-values */
6554                         offset = fSequenceOfEnums(tvb, pinfo, tree, offset, "masked-alarm-value: ", BACnetDoorAlarmState);
6555                         break;
6556                 case 53:        /* list-of-group-members */
6557                         save_object_type = object_type;
6558                         offset = fListOfGroupMembers(tvb, pinfo, tree, offset);
6559                         object_type = save_object_type;
6560                         break;
6561                 case 85:    /* present-value */
6562                         if ( object_type == 11 )        /* group object handling of present-value */
6563                         {
6564                                 offset = fReadAccessResult(tvb, pinfo, tree, offset);
6565                                 break;
6566                         }
6567                         /* intentially fall through here so don't reorder this case statement */
6568                 default:
6569                         if (tag_info) {
6570                                 if (tag_is_opening(tag_info)) {
6571                                         ++depth;
6572                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
6573                                 } else if (tag_is_closing(tag_info)) {
6574                                         --depth;
6575                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
6576                                 } else {
6577                                         offset = fContextTaggedValue(tvb, tree, offset, ar);
6578                                 }
6579                         } else {
6580                                 offset = fApplicationTypes (tvb, pinfo, tree, offset, ar);
6581                         }
6582                         break;
6583                 }
6584                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6585         }
6586         return offset;
6587
6588 }
6589
6590 static guint
6591 fPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tag_info)
6592 {
6593         guint8 tag_no;
6594         guint32 lvt;
6595
6596         if (tag_is_opening(tag_info)) {
6597                 offset += fTagHeaderTree(tvb, tree, offset,
6598                         &tag_no, &tag_info, &lvt);
6599                 offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset);
6600                 if (tvb_length_remaining(tvb, offset) > 0) {
6601                         offset += fTagHeaderTree(tvb, tree, offset,
6602                                 &tag_no, &tag_info, &lvt);
6603                 }
6604         } else {
6605                 proto_tree_add_text(tree, tvb, offset, tvb_length(tvb) - offset,
6606                         "expected Opening Tag!"); \
6607                 offset = tvb_length(tvb);
6608         }
6609
6610         return offset;
6611 }
6612
6613
6614 static guint
6615 fPropertyIdentifierValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset)
6616 {
6617         guint lastoffset = offset;
6618         guint8 tag_no, tag_info;
6619         guint32 lvt;
6620
6621         offset = fPropertyReference(tvb, pinfo, tree, offset, tagoffset, 0);
6622         if (offset > lastoffset) {
6623                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6624                 if (tag_no == tagoffset+2) {  /* Value - might not be present in ReadAccessResult */
6625                         offset = fPropertyValue (tvb, pinfo, tree, offset, tag_info);
6626                 }
6627         }
6628         return offset;
6629 }
6630
6631 static guint
6632 fBACnetPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6633 {
6634         guint lastoffset = 0;
6635         guint8 tag_no, tag_info;
6636         guint32 lvt;
6637
6638         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6639                 lastoffset = offset;
6640                 offset = fPropertyIdentifierValue(tvb, pinfo, tree, offset, 0);
6641                 if (offset > lastoffset) {
6642                         /* detect optional priority
6643                         by looking to see if the next tag is context tag number 3 */
6644                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6645                         if (tag_is_context_specific(tag_info) && (tag_no == 3))
6646                                 offset = fUnsignedTag (tvb,tree,offset,"Priority: ");
6647                 }
6648                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6649         }
6650         return offset;
6651 }
6652
6653 static guint
6654 fSubscribeCOVPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6655 {
6656         guint lastoffset = 0, len;
6657         guint8 tag_no, tag_info;
6658         guint32 lvt;
6659         proto_tree *subtree = tree;
6660         proto_item *tt;
6661
6662         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6663                 lastoffset = offset;
6664                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6665                 if (tag_is_closing(tag_info)) {
6666                         offset += len;
6667                         subtree = tree;
6668                         continue;
6669                 }
6670
6671                 switch (tag_no) {
6672                 case 0: /* ProcessId */
6673                         offset = fUnsignedTag (tvb, tree, offset, "subscriber Process Id: ");
6674                         break;
6675                 case 1: /* monitored ObjectId */
6676                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
6677                         break;
6678                 case 2: /* issueConfirmedNotifications */
6679                         offset = fBooleanTag (tvb, tree, offset, "issue Confirmed Notifications: ");
6680                         break;
6681                 case 3: /* life time */
6682                         offset = fTimeSpan (tvb,tree,offset,"life time");
6683                         break;
6684                 case 4: /* monitoredPropertyIdentifier */
6685                         if (tag_is_opening(tag_info)) {
6686                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "monitoredPropertyIdentifier");
6687                                 if (tt) {
6688                                         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
6689                                 }
6690                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
6691                                 offset = fBACnetPropertyReference (tvb, pinfo, subtree, offset, 1);
6692                                 break;
6693                         }
6694                         FAULT;
6695                         break;
6696                 case 5: /* covIncrement */
6697                         offset = fRealTag (tvb, tree, offset, "COV Increment: ");
6698                         break;
6699                 default:
6700                         return offset;
6701                 }
6702                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6703         }
6704         return offset;
6705 }
6706
6707 static guint
6708 fSubscribeCOVRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6709 {
6710         return fSubscribeCOVPropertyRequest(tvb, pinfo, tree, offset);
6711 }
6712
6713 static guint
6714 fWhoHas (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6715 {
6716         guint lastoffset = 0;
6717
6718         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6719                 lastoffset = offset;
6720
6721                 switch (fTagNo(tvb, offset)) {
6722                 case 0: /* deviceInstanceLowLimit */
6723                         offset = fUnsignedTag (tvb, tree, offset, "device Instance Low Limit: ");
6724                         break;
6725                 case 1: /* deviceInstanceHighLimit */
6726                         offset = fUnsignedTag (tvb, tree, offset, "device Instance High Limit: ");
6727                         break;
6728                 case 2: /* BACnetObjectId */
6729                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
6730                         break;
6731                 case 3: /* messageText */
6732                         offset = fCharacterString (tvb,tree,offset, "Object Name: ");
6733                         break;
6734                 default:
6735                         return offset;
6736                 }
6737                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6738         }
6739         return offset;
6740 }
6741
6742
6743 static guint
6744 fDailySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset)
6745 {
6746         guint lastoffset = 0;
6747         guint8 tag_no, tag_info;
6748         guint32 lvt;
6749
6750         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6751         if (tag_is_opening(tag_info) && tag_no == 0) {
6752                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt); /* opening context tag 0 */
6753                 while (tvb_reported_length_remaining(tvb, offset) > 0) {  /* exit loop if nothing happens inside */
6754                         lastoffset = offset;
6755                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6756                         if (tag_is_closing(tag_info)) {
6757                                 /* should be closing context tag 0 */
6758                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
6759                                 return offset;
6760                         }
6761
6762                         offset = fTimeValue (tvb, pinfo, subtree, offset);
6763                         if (offset == lastoffset) break;    /* nothing happened, exit loop */
6764                 }
6765         } else if (tag_no == 0 && lvt == 0) {
6766                 /* not sure null (empty array element) is legal */
6767                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
6768         }
6769         return offset;
6770 }
6771
6772 static guint
6773 fWeeklySchedule (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6774 {
6775         guint lastoffset = 0;
6776         guint8 tag_no, tag_info;
6777         guint32 lvt;
6778         guint i = 1; /* day of week array index */
6779         proto_tree *subtree = tree;
6780         proto_item *tt;
6781
6782         if (propertyArrayIndex > 0) {
6783                 /* BACnetARRAY index 0 refers to the length
6784                 of the array, not the elements of the array.
6785                 BACnetARRAY index -1 is our internal flag that
6786                 the optional index was not used.
6787                 BACnetARRAY refers to this as all elements of the array.
6788                 If the optional index is specified for a BACnetARRAY,
6789                 then that specific array element is referenced. */
6790                 i = propertyArrayIndex;
6791         }
6792         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6793                 lastoffset = offset;
6794                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6795                 if (tag_is_closing(tag_info)) {
6796                         return offset; /* outer encoding will print out closing tag */
6797                 }
6798                 tt = proto_tree_add_text(tree, tvb, offset, 0, "%s", val_to_str(i++, day_of_week, "day of week (%d) not found"));
6799                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
6800                 offset = fDailySchedule (tvb, pinfo, subtree, offset);
6801                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6802         }
6803         return offset;
6804 }
6805
6806
6807 static guint
6808 fUTCTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
6809 {
6810         if (tvb_reported_length_remaining(tvb, offset) <= 0)
6811                 return offset;
6812
6813         return fDateTime (tvb, tree, offset, "UTC-Time: ");
6814 }
6815
6816 static guint
6817 fTimeSynchronizationRequest  (tvbuff_t *tvb, proto_tree *tree, guint offset)
6818 {
6819         if (tvb_reported_length_remaining(tvb, offset) <= 0)
6820                 return offset;
6821
6822         return fDateTime (tvb, tree, offset, NULL);
6823 }
6824
6825 static guint
6826 fDateRange  (tvbuff_t *tvb, proto_tree *tree, guint offset)
6827 {
6828         if (tvb_reported_length_remaining(tvb, offset) <= 0)
6829                 return offset;
6830         offset = fDate (tvb,tree,offset,"Start Date: ");
6831         return fDate (tvb, tree, offset, "End Date: ");
6832 }
6833
6834 static guint
6835 fVendorIdentifier (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6836 {
6837         guint32 val = 0;
6838         guint8 tag_no, tag_info;
6839         guint32 lvt;
6840         guint tag_len;
6841         proto_item *ti;
6842         proto_tree *subtree;
6843         const gchar *label = "Vendor ID";
6844
6845         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6846         if (fUnsigned32 (tvb, offset + tag_len, lvt, &val))
6847                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
6848                         "%s: %s (%u)", label,
6849                         val_to_str(val,BACnetVendorIdentifiers,"Unknown Vendor"), val);
6850         else
6851                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
6852                         "%s - %u octets (Unsigned)", label, lvt);
6853         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
6854         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
6855
6856         if ((lvt < 1) || (lvt > 2)) { /* vendorIDs >= 1  and <= 2 are supported */
6857                 proto_item *expert_item;
6858                 expert_item = proto_tree_add_text(tree, tvb, 0, lvt, "Wrong length indicated. Expected 1 or 2, got %u", lvt);
6859                 expert_add_info_format(pinfo, expert_item, PI_MALFORMED, PI_ERROR, "Wrong length indicated. Expected 1 or 2, got %u", lvt);
6860                 PROTO_ITEM_SET_GENERATED(expert_item);
6861                 return offset+tag_len+lvt;
6862         }
6863
6864         proto_tree_add_item(subtree, hf_BACnetVendorIdentifier, tvb,
6865                 offset+tag_len, lvt, ENC_BIG_ENDIAN);
6866
6867         return offset+tag_len+lvt;
6868 }
6869
6870 static guint
6871 fRestartReason (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6872 {
6873         guint32 val = 0;
6874         guint8 tag_no, tag_info;
6875         guint32 lvt;
6876         guint tag_len;
6877         proto_item *ti;
6878         proto_tree *subtree;
6879         const gchar *label = "Restart Reason";
6880
6881         tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6882         if (fUnsigned32 (tvb, offset + tag_len, lvt, &val))
6883                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
6884                         "%s: %s (%u)", label,
6885                         val_to_str(val,BACnetRestartReason,"Unknown reason"), val);
6886         else
6887                 ti = proto_tree_add_text(tree, tvb, offset, lvt+tag_len,
6888                         "%s - %u octets (Unsigned)", label, lvt);
6889         subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
6890         fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
6891
6892         if (lvt != 1) {
6893                 proto_item *expert_item;
6894                 expert_item = proto_tree_add_text(tree, tvb, 0, lvt, "Wrong length indicated. Expected 1, got %u", lvt);
6895                 expert_add_info_format(pinfo, expert_item, PI_MALFORMED, PI_ERROR, "Wrong length indicated. Expected 1, got %u", lvt);
6896                 PROTO_ITEM_SET_GENERATED(expert_item);
6897                 return offset+tag_len+lvt;
6898         }
6899
6900         proto_tree_add_item(subtree, hf_BACnetRestartReason, tvb,
6901                 offset+tag_len, lvt, ENC_BIG_ENDIAN);
6902
6903         return offset+tag_len+lvt;
6904 }
6905
6906 static guint
6907 fConfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6908 {
6909         guint lastoffset = 0;
6910
6911         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
6912                 lastoffset = offset;
6913                 switch (fTagNo(tvb, offset)) {
6914
6915                 case 0: /* textMessageSourceDevice */
6916                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
6917                         break;
6918                 case 1: /* messageClass */
6919                         switch (fTagNo(tvb, offset)) {
6920                         case 0: /* numeric */
6921                                 offset = fUnsignedTag (tvb, tree, offset, "message Class: ");
6922                                 break;
6923                         case 1: /* character */
6924                                 offset = fCharacterString (tvb, tree, offset, "message Class: ");
6925                                 break;
6926                         }
6927                         break;
6928                 case 2: /* messagePriority */
6929                         offset = fEnumeratedTag (tvb, tree, offset, "message Priority: ",
6930                                 BACnetMessagePriority);
6931                         break;
6932                 case 3: /* message */
6933                         offset = fCharacterString (tvb, tree, offset, "message: ");
6934                         break;
6935                 default:
6936                         return offset;
6937                 }
6938                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
6939         }
6940         return offset;
6941 }
6942
6943 static guint
6944 fUnconfirmedTextMessageRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6945 {
6946         return fConfirmedTextMessageRequest(tvb, pinfo, tree, offset);
6947 }
6948
6949 static guint
6950 fConfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
6951 {
6952         guint lastoffset = 0, len;
6953         guint8 tag_no, tag_info;
6954         guint32 lvt;
6955         proto_tree *subtree = tree;
6956         proto_item *tt;
6957         tvbuff_t *next_tvb;
6958         guint vendor_identifier = 0;
6959         guint service_number = 0;
6960
6961         lastoffset = offset;
6962         len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6963         fUnsigned32(tvb, offset+len, lvt, &vendor_identifier);
6964         if (col_get_writable(pinfo->cinfo))
6965                 col_append_fstr(pinfo->cinfo, COL_INFO, "V=%u ", vendor_identifier);
6966         offset = fVendorIdentifier (tvb, pinfo, subtree, offset);
6967
6968         next_tvb = tvb_new_subset_remaining(tvb,offset);
6969         if (dissector_try_uint(bacapp_dissector_table,
6970             vendor_identifier, next_tvb, pinfo, tree)) {
6971                 /* we parsed it so skip over length and we are done */
6972                 offset += tvb_length(next_tvb);
6973                 return offset;
6974         }
6975
6976         /* Not handled by vendor dissector */
6977
6978         /* exit loop if nothing happens inside */
6979         while (tvb_reported_length_remaining(tvb, offset)) {
6980                 lastoffset = offset;
6981                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
6982                 if (tag_is_closing(tag_info)) {
6983                         if (tag_no == 2) { /* Make sure it's the expected tag */
6984                                 offset += len;
6985                                 subtree = tree;
6986                                 continue;
6987                         } else {
6988                                 break; /* End loop if incorrect closing tag */
6989                         }
6990                 }
6991                 switch (tag_no) {
6992
6993                         /* vendorID is now parsed above */
6994                 case 1: /* serviceNumber */
6995                         fUnsigned32(tvb, offset+len, lvt, &service_number);
6996                         if (col_get_writable(pinfo->cinfo))
6997                                 col_append_fstr(pinfo->cinfo, COL_INFO, "SN=%u ",       service_number);
6998                         offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
6999                         break;
7000                 case 2: /*serviceParameters */
7001                         if (tag_is_opening(tag_info)) {
7002                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "service Parameters");
7003                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
7004                                 propertyIdentifier = -1;
7005                                 offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset);
7006                                 break;
7007                         }
7008                         FAULT;
7009                         break;
7010                 default:
7011                         return offset;
7012                 }
7013                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
7014         }
7015
7016         return offset;
7017 }
7018
7019 static guint
7020 fUnconfirmedPrivateTransferRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7021 {
7022         return fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset);
7023 }
7024
7025 static guint
7026 fConfirmedPrivateTransferAck(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7027 {
7028         return fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset);
7029 }
7030
7031 static guint
7032 fLifeSafetyOperationRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, const gchar *label)
7033 {
7034         guint lastoffset = 0;
7035         guint8 tag_no, tag_info;
7036         guint32 lvt;
7037         proto_tree *subtree = tree;
7038         proto_item *tt;
7039
7040         if (label != NULL) {
7041                 tt = proto_tree_add_text (subtree, tvb, offset, 1, "%s", label);
7042                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
7043         }
7044
7045         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7046                 lastoffset = offset;
7047                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7048
7049                 switch (tag_no) {
7050                 case 0: /* subscriberProcessId */
7051                         offset = fUnsignedTag (tvb, subtree, offset, "requesting Process Id: ");
7052                         break;
7053                 case 1: /* requestingSource */
7054                         offset = fCharacterString (tvb, tree, offset, "requesting Source: ");
7055                         break;
7056                 case 2: /* request */
7057                         offset = fEnumeratedTagSplit (tvb, tree, offset,
7058                                 "request: ", BACnetLifeSafetyOperation, 64);
7059                         break;
7060                 case 3: /* objectId */
7061                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
7062                         break;
7063                 default:
7064                         return offset;
7065                 }
7066                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
7067         }
7068         return offset;
7069 }
7070
7071 typedef struct _value_string_enum {
7072         const value_string *valstr;
7073 } value_string_enum;
7074
7075 static const value_string_enum
7076 BACnetPropertyStatesEnums[] = {
7077         { NULL },
7078         {BACnetBinaryPV },
7079         {BACnetEventType },
7080         {BACnetPolarity },
7081         {BACnetProgramRequest },
7082         {BACnetProgramState },
7083         {BACnetProgramError },
7084         {BACnetReliability },
7085         {BACnetEventState },
7086         {BACnetDeviceStatus },
7087         {BACnetEngineeringUnits },
7088         { NULL },
7089         {BACnetLifeSafetyMode },
7090         {BACnetLifeSafetyState },
7091         {BACnetRestartReason },
7092         {BACnetDoorAlarmState },
7093         {BACnetAction },
7094         {BACnetDoorSecuredStatus },
7095         {BACnetDoorStatus },
7096         { NULL }, /* {BACnetDoorValue }, */
7097         {BACnetFileAccessMethod },
7098         {BACnetLockStatus },
7099         {BACnetLifeSafetyOperation },
7100         {BACnetMaintenance },
7101         {BACnetNodeType },
7102         {BACnetNotifyType },
7103         { NULL }, /* {BACnetSecurityLevel }, */
7104         {BACnetShedState },
7105         {BACnetSilencedState },
7106         { NULL },
7107         { NULL }, /* {BACnetAccessEvent }, */
7108         { NULL }, /* {BACnetZoneOccupancyState }, */
7109         { NULL }, /* {BACnetAccessCredentialDisableReason }, */
7110         { NULL }, /* {BACnetAccessCredentialDisable }, */
7111         { NULL }, /* {BACnetAuthenticationStatus }, */
7112         { NULL },
7113         { NULL }, /* {BACnetBackupState }, */
7114 };
7115 #define BACnetPropertyStatesEnums_Size 36
7116
7117 static guint
7118 fBACnetPropertyStates(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint offset)
7119 {
7120         guint8 tag_no, tag_info;
7121         guint32 lvt;
7122         const gchar* label = NULL;
7123
7124         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7125         label = ep_strdup_printf( "%s: ", val_to_str_const( tag_no, VALS(BACnetPropertyStates), "unknown-"+tag_no ));
7126
7127         switch (tag_no)
7128         {
7129         case 0:
7130                 offset = fBooleanTag (tvb, tree, offset, label);
7131                 break;
7132         case 11:
7133                 offset = fUnsignedTag(tvb, tree, offset, label);
7134                 break;
7135         default:
7136                 if ( (tag_no > BACnetPropertyStatesEnums_Size) ||
7137                         VALS(BACnetPropertyStatesEnums[tag_no].valstr) == NULL)
7138                 {
7139                         offset = fEnumeratedTag(tvb, tree, offset, "Unknown State: ", NULL);
7140                         /* don't use Abstract type here because it is context tagged and therefore we don't know app type */
7141                 }
7142                 else
7143                 {
7144                         offset = fEnumeratedTagSplit(tvb, tree, offset, label,
7145                                         VALS(BACnetPropertyStatesEnums[tag_no].valstr), 64);
7146                 }
7147                 break;
7148         }
7149         return offset;
7150 }
7151
7152
7153 /*
7154 BACnetDeviceObjectPropertyValue ::= SEQUENCE {
7155       deviceIdentifier       [0]      BACnetObjectIdentifier,
7156       objectIdentifier       [1]      BACnetObjectIdentifier,
7157       propertyIdentifier     [2]      BACnetPropertyIdentifier,
7158       arrayIndex             [3]      Unsigned OPTIONAL,
7159       value                  [4]      ABSTRACT-SYNTAX.&Type
7160       }
7161 */
7162 static guint
7163 fDeviceObjectPropertyValue (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7164 {
7165         guint lastoffset = 0;
7166         guint8 tag_no, tag_info;
7167         guint32 lvt;
7168
7169         while (tvb_reported_length_remaining(tvb, offset)) {
7170                 lastoffset = offset;
7171                 /* check the tag.  A closing tag means we are done */
7172                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7173                 if (tag_is_closing(tag_info)) {
7174                         return offset;
7175                 }
7176                 switch (tag_no) {
7177                 case 0: /* deviceIdentifier */
7178                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
7179                         break;
7180                 case 1: /* objectIdentifier */
7181                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
7182                         break;
7183                 case 2: /* propertyIdentifier */
7184                         offset = fPropertyIdentifier (tvb, pinfo, tree, offset);
7185                         break;
7186                 case 3: /* arrayIndex - OPTIONAL */
7187                         offset = fUnsignedTag (tvb, tree, offset,
7188                                 "arrayIndex: ");
7189                         break;
7190                 case 4: /* value */
7191                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
7192                         offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset);
7193                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
7194                         break;
7195                 default:
7196                         return offset;
7197                 }
7198                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
7199         }
7200         return offset;
7201 }
7202
7203 /*
7204 BACnetDeviceObjectPropertyReference ::= SEQUENCE {
7205       objectIdentifier       [0]      BACnetObjectIdentifier,
7206       propertyIdentifier     [1]      BACnetPropertyIdentifier,
7207       propertyArrayIndex     [2]      Unsigned OPTIONAL, -- used only with array datatype
7208                                                                 -- if omitted with an array then
7209                                                                 -- the entire array is referenced
7210       deviceIdentifier       [3]      BACnetObjectIdentifier OPTIONAL
7211       }
7212 */
7213 static guint
7214 fObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7215 {
7216         return fDeviceObjectPropertyReference(tvb, pinfo, tree, offset);
7217 }
7218
7219 /*
7220 BACnetDeviceObjectPropertyReference ::= SEQUENCE {
7221       objectIdentifier       [0]      BACnetObjectIdentifier,
7222       propertyIdentifier     [1]      BACnetPropertyIdentifier,
7223       propertyArrayIndex     [2]      Unsigned OPTIONAL, -- used only with array datatype
7224                                                                 -- if omitted with an array then
7225                                                                 -- the entire array is referenced
7226       deviceIdentifier       [3]      BACnetObjectIdentifier OPTIONAL
7227       }
7228 */
7229 static guint
7230 fDeviceObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7231 {
7232         guint lastoffset = 0;
7233         guint8 tag_no, tag_info;
7234         guint32 lvt;
7235
7236         while (tvb_reported_length_remaining(tvb, offset)) {
7237                 lastoffset = offset;
7238                 /* check the tag.  A closing tag means we are done */
7239                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7240                 if (tag_is_closing(tag_info)) {
7241                         return offset;
7242                 }
7243                 switch (tag_no) {
7244                 case 0: /* objectIdentifier */
7245                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
7246                         break;
7247                 case 1: /* propertyIdentifier */
7248                         offset = fPropertyIdentifier (tvb, pinfo, tree, offset);
7249                         break;
7250                 case 2: /* arrayIndex - OPTIONAL */
7251                         offset = fUnsignedTag (tvb, tree, offset,
7252                                 "arrayIndex: ");
7253                         break;
7254                 case 3: /* deviceIdentifier - OPTIONAL */
7255                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
7256                         break;
7257                 default:
7258                         return offset;
7259                 }
7260                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
7261         }
7262         return offset;
7263 }
7264
7265 static guint
7266 fNotificationParameters (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7267 {
7268         guint lastoffset = offset;
7269         guint8 tag_no, tag_info;
7270         guint32 lvt;
7271         proto_tree *subtree = tree;
7272         proto_item *tt;
7273
7274         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7275         tt = proto_tree_add_text(subtree, tvb, offset, 0, "notification parameters (%d) %s",
7276                 tag_no, val_to_str(tag_no, BACnetEventType, "invalid type"));
7277         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
7278         /* Opening tag for parameter choice */
7279         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7280
7281         switch (tag_no) {
7282         case 0: /* change-of-bitstring */
7283                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7284                         lastoffset = offset;
7285                         switch (fTagNo(tvb, offset)) {
7286                         case 0:
7287                                 offset = fBitStringTag (tvb, subtree, offset,
7288                                         "referenced-bitstring: ");
7289                                 break;
7290                         case 1:
7291                                 offset = fBitStringTagVS (tvb, subtree, offset,
7292                                         "status-flags: ", BACnetStatusFlags);
7293                         lastoffset = offset;
7294                                 break;
7295                         default:
7296                                 break;
7297                         }
7298                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7299                 }
7300                 break;
7301         case 1: /* change-of-state */
7302                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7303                         lastoffset = offset;
7304                         switch (fTagNo(tvb, offset)) {
7305                         case 0:
7306                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7307                                 offset = fBACnetPropertyStates(tvb, pinfo, subtree, offset);
7308                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7309                                 break;
7310                         case 1:
7311                                 offset = fBitStringTagVS (tvb, subtree, offset,
7312                                         "status-flags: ", BACnetStatusFlags);
7313                         lastoffset = offset;
7314                                 break;
7315                         default:
7316                                 break;
7317                         }
7318                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7319                 }
7320                 break;
7321         case 2: /* change-of-value */
7322                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7323                         lastoffset = offset;
7324                         switch (fTagNo(tvb, offset)) {
7325                         case 0:
7326                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7327                                 switch (fTagNo(tvb, offset)) {
7328                                 case 0:
7329                                         offset = fBitStringTag (tvb, subtree, offset,
7330                                                 "changed-bits: ");
7331                                         break;
7332                                 case 1:
7333                                         offset = fRealTag (tvb, subtree, offset,
7334                                                 "changed-value: ");
7335                                         break;
7336                                 default:
7337                                         break;
7338                                 }
7339                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7340                                 break;
7341                         case 1:
7342                                 offset = fBitStringTagVS (tvb, subtree, offset,
7343                                         "status-flags: ", BACnetStatusFlags);
7344                         lastoffset = offset;
7345                                 break;
7346                         default:
7347                                 break;
7348                         }
7349                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7350                 }
7351                 break;
7352         case 3: /* command-failure */
7353                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7354                         lastoffset = offset;
7355                         switch (fTagNo(tvb, offset)) {
7356                         case 0: /* "command-value: " */
7357                                 /* from BACnet Table 13-3,
7358                                         Standard Object Property Values Returned in Notifications */
7359                                 propertyIdentifier = 85; /* PRESENT_VALUE */
7360                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7361                                 offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset);
7362                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7363                                 break;
7364                         case 1:
7365                                 offset = fBitStringTagVS (tvb, subtree, offset,
7366                                         "status-flags: ", BACnetStatusFlags);
7367                                 break;
7368                         case 2: /* "feedback-value: " */
7369                                 propertyIdentifier = 40; /* FEEDBACK_VALUE */
7370                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7371                                 offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset);
7372                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7373                         lastoffset = offset;
7374                                 break;
7375                         default:
7376                                 break;
7377                         }
7378                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7379                 }
7380                 break;
7381         case 4: /* floating-limit */
7382                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7383                         lastoffset = offset;
7384                         switch (fTagNo(tvb, offset)) {
7385                         case 0:
7386                                 offset = fRealTag (tvb, subtree, offset, "reference-value: ");
7387                                 break;
7388                         case 1:
7389                                 offset = fBitStringTagVS (tvb, subtree, offset,
7390                                         "status-flags: ", BACnetStatusFlags);
7391                                 break;
7392                         case 2:
7393                                 offset = fRealTag (tvb, subtree, offset, "setpoint-value: ");
7394                                 break;
7395                         case 3:
7396                                 offset = fRealTag (tvb, subtree, offset, "error-limit: ");
7397                         lastoffset = offset;
7398                                 break;
7399                         default:
7400                                 break;
7401                         }
7402                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7403                 }
7404                 break;
7405         case 5: /* out-of-range */
7406                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7407                         lastoffset = offset;
7408                         switch (fTagNo(tvb, offset)) {
7409                         case 0:
7410                                 offset = fRealTag (tvb, subtree, offset, "exceeding-value: ");
7411                                 break;
7412                         case 1:
7413                                 offset = fBitStringTagVS (tvb, subtree, offset,
7414                                         "status-flags: ", BACnetStatusFlags);
7415                                 break;
7416                         case 2:
7417                                 offset = fRealTag (tvb, subtree, offset, "deadband: ");
7418                                 break;
7419                         case 3:
7420                                 offset = fRealTag (tvb, subtree, offset, "exceeded-limit: ");
7421                         lastoffset = offset;
7422                                 break;
7423                         default:
7424                                 break;
7425                         }
7426                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7427                 }
7428             break;
7429         case 6:
7430                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7431                         lastoffset = offset;
7432                         offset =fBACnetPropertyValue (tvb,pinfo,subtree,offset);
7433                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7434                 }
7435                 break;
7436         case 7: /* buffer-ready */
7437                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7438                         lastoffset = offset;
7439                         switch (fTagNo(tvb, offset)) {
7440                         case 0:
7441                                 offset = fObjectIdentifier (tvb, pinfo, subtree, offset); /* buffer-device */
7442                                 break;
7443                         case 1:
7444                                 offset = fObjectIdentifier (tvb, pinfo, subtree, offset); /* buffer-object */
7445                                 break;
7446                         case 2:
7447                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7448                                 offset = fDateTime (tvb, subtree, offset, "previous-notification: ");
7449                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7450                                 break;
7451                         case 3:
7452                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7453                                 offset = fDateTime (tvb, subtree, offset, "current-notification: ");
7454                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7455                         lastoffset = offset;
7456                                 break;
7457                         default:
7458                                 break;
7459                         }
7460                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7461                 }
7462                 break;
7463         case 8: /* change-of-life-safety */
7464                 while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7465                         lastoffset = offset;
7466                         switch (fTagNo(tvb, offset)) {
7467                         case 0:
7468                                 offset = fEnumeratedTagSplit (tvb, subtree, offset,
7469                                         "new-state: ", BACnetLifeSafetyState, 256);
7470                                 break;
7471                         case 1:
7472                                 offset = fEnumeratedTagSplit (tvb, subtree, offset,
7473                                         "new-mode: ", BACnetLifeSafetyMode, 256);
7474                                 break;
7475                         case 2:
7476                                 offset = fBitStringTagVS (tvb, subtree, offset,
7477                                         "status-flags: ", BACnetStatusFlags);
7478                                 break;
7479                         case 3:
7480                                 offset = fEnumeratedTagSplit (tvb, subtree, offset,
7481                                         "operation-expected: ", BACnetLifeSafetyOperation, 64);
7482                         lastoffset = offset;
7483                                 break;
7484                         default:
7485                                 break;
7486                         }
7487                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7488                 }
7489                 break;
7490         case 9: /* extended */
7491                 while (tvb_reported_length_remaining(tvb, offset)) {
7492                         lastoffset = offset;
7493                         switch (fTagNo(tvb, offset)) {
7494                         case 0:
7495                                 offset = fVendorIdentifier (tvb, pinfo, subtree, offset);
7496                                 break;
7497                         case 1:
7498                                 offset = fUnsignedTag (tvb, subtree, offset,
7499                                         "extended-event-type: ");
7500                                 break;
7501                         case 2: /* parameters */
7502                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7503                                 offset = fApplicationTypes(tvb, pinfo, subtree, offset, "parameters: ");
7504                                 offset = fDeviceObjectPropertyValue(tvb, pinfo, subtree, offset);
7505                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7506                         lastoffset = offset;
7507                                 break;
7508                         default:
7509                                 break;
7510                         }
7511                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7512                 }
7513                 break;
7514         case 10: /* buffer ready */
7515                 while (tvb_reported_length_remaining(tvb, offset)) {
7516                         lastoffset = offset;
7517                         switch (fTagNo(tvb, offset)) {
7518                         case 0: /* buffer-property */
7519                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7520                                 offset = fDeviceObjectPropertyReference (tvb, pinfo, subtree, offset);
7521                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7522                                 break;
7523                         case 1:
7524                                 offset = fUnsignedTag (tvb, subtree, offset,
7525                                         "previous-notification: ");
7526                                 break;
7527                         case 2:
7528                                 offset = fUnsignedTag (tvb, subtree, offset,
7529                                         "current-notification: ");
7530                         lastoffset = offset;
7531                                 break;
7532                         default:
7533                                 break;
7534                         }
7535                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7536                 }
7537                 break;
7538         case 11: /* unsigned range */
7539                 while (tvb_reported_length_remaining(tvb, offset)) {
7540                         lastoffset = offset;
7541                         switch (fTagNo(tvb, offset)) {
7542                         case 0:
7543                                 offset = fUnsignedTag (tvb, subtree, offset,
7544                                         "exceeding-value: ");
7545                                 break;
7546                         case 1:
7547                                 offset = fBitStringTagVS (tvb, subtree, offset,
7548                                         "status-flags: ", BACnetStatusFlags);
7549                                 break;
7550                         case 2:
7551                                 offset = fUnsignedTag (tvb, subtree, offset,
7552                                         "exceeded-limit: ");
7553                         lastoffset = offset;
7554                                 break;
7555                         default:
7556                                 break;
7557                         }
7558                         if (offset == lastoffset) break;     /* nothing happened, exit loop */
7559                 }
7560                 break;
7561                 /* todo: add new parameters here ... */
7562         default:
7563                 offset = fAbstractSyntaxNType(tvb, pinfo, subtree, offset);
7564                 break;
7565         }
7566
7567         /* Closing tag for parameter choice */
7568         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7569
7570         return offset;
7571 }
7572
7573 static guint
7574 fEventParameter (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7575 {
7576         guint lastoffset = offset;
7577         guint8 tag_no, tag_info;
7578         guint32 lvt;
7579         proto_tree *subtree = tree;
7580         proto_item *tt;
7581
7582         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7583         tt = proto_tree_add_text(subtree, tvb, offset, 0, "event parameters (%d) %s",
7584                 tag_no, val_to_str(tag_no, BACnetEventType, "invalid type"));
7585         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
7586         /* Opening tag for parameter choice */
7587         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7588
7589         switch (tag_no) {
7590                 case 0: /* change-of-bitstring */
7591                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7592                                 lastoffset = offset;
7593                                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7594                                 if (tag_is_closing(tag_info)) {
7595                                         break;
7596                                 }
7597                                 switch (tag_no) {
7598                                 case 0:
7599                                         offset = fTimeSpan (tvb, subtree, offset, "Time Delay");
7600                                         break;
7601                                 case 1:
7602                                         offset = fBitStringTag (tvb, subtree, offset, "bitmask: ");
7603                                         break;
7604                                 case 2: /* SEQUENCE OF BIT STRING */
7605                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7606                                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7607                                                 lastoffset = offset;
7608                                                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7609                                                 if (tag_is_closing(tag_info)) {
7610                                                         break;
7611                                                 }
7612                                         offset = fBitStringTag(tvb, subtree, offset,
7613                                                 "bitstring value: ");
7614                                         }
7615                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7616                                         break;
7617                                 default:
7618                                         break;
7619                                 }
7620                         }
7621                         break;
7622                 case 1: /* change-of-state */
7623                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7624                                 lastoffset = offset;
7625                                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7626                                 if (tag_is_closing(tag_info)) {
7627                                         break;
7628                                 }
7629                                 switch (tag_no) {
7630                                 case 0:
7631                                         offset = fTimeSpan (tvb, subtree, offset, "Time Delay");
7632                                         break;
7633                                 case 1: /* SEQUENCE OF BACnetPropertyStates */
7634                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7635                                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7636                                                 lastoffset = offset;
7637                                                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7638                                                 if (tag_is_closing(tag_info)) {
7639                                                         break;
7640                                                 }
7641                                                 offset = fBACnetPropertyStates(tvb, pinfo, subtree, offset);
7642                                         }
7643                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7644                                         break;
7645                                 default:
7646                                         break;
7647                                 }
7648                         }
7649                         break;
7650                 case 2: /* change-of-value */
7651                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7652                                 lastoffset = offset;
7653                                 switch (fTagNo(tvb, offset)) {
7654                                 case 0:
7655                                         offset = fTimeSpan   (tvb, subtree, offset, "Time Delay");
7656                                         break;
7657                                 case 1: /* don't loop it, it's a CHOICE */
7658                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7659                                         switch (fTagNo(tvb, offset)) {
7660                                         case 0:
7661                                                 offset = fBitStringTag (tvb, subtree, offset, "bitmask: ");
7662                                                 break;
7663                                         case 1:
7664                                                 offset = fRealTag (tvb, subtree, offset,
7665                                                         "referenced Property Increment: ");
7666                                                 break;
7667                                         default:
7668                                                 break;
7669                                         }
7670                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7671                                         break;
7672                                 default:
7673                                         break;
7674                                 }
7675                         }
7676                         break;
7677                 case 3: /* command-failure */
7678                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7679                                 lastoffset = offset;
7680                                 tag_no = fTagNo(tvb, offset);
7681                                 switch (tag_no) {
7682                                 case 0:
7683                                         offset = fTimeSpan   (tvb, subtree, offset, "Time Delay");
7684                                         break;
7685                                 case 1:
7686                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7687                                         offset = fDeviceObjectPropertyReference (tvb,pinfo,subtree,offset);
7688                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7689                                         break;
7690                                 default:
7691                                         break;
7692                                 }
7693                         }
7694                         break;
7695                 case 4: /* floating-limit */
7696                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7697                                 lastoffset = offset;
7698                                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7699                                 if (tag_is_closing(tag_info)) {
7700                                         break;
7701                                 }
7702                                 switch (tag_no) {
7703                                 case 0:
7704                                         offset = fTimeSpan   (tvb, subtree, offset, "Time Delay");
7705                                         break;
7706                                 case 1:
7707                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7708                                         offset = fDeviceObjectPropertyReference (tvb,pinfo,subtree,offset);
7709                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7710                                         break;
7711                                 case 2:
7712                                         offset = fRealTag (tvb, subtree, offset, "low diff limit: ");
7713                                         break;
7714                                 case 3:
7715                                         offset = fRealTag (tvb, subtree, offset, "high diff limit: ");
7716                                         break;
7717                                 case 4:
7718                                         offset = fRealTag (tvb, subtree, offset, "deadband: ");
7719                                         break;
7720                                 default:
7721                                         break;
7722                                 }
7723                         }
7724                         break;
7725                 case 5: /* out-of-range */
7726                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7727                                 lastoffset = offset;
7728                                 switch (fTagNo(tvb, offset)) {
7729                                 case 0:
7730                                         offset = fTimeSpan (tvb, subtree, offset, "Time Delay");
7731                                         break;
7732                                 case 1:
7733                                         offset = fRealTag (tvb, subtree, offset, "low limit: ");
7734                                         break;
7735                                 case 2:
7736                                         offset = fRealTag (tvb, subtree, offset, "high limit: ");
7737                                         break;
7738                                 case 3:
7739                                         offset = fRealTag (tvb, subtree, offset, "deadband: ");
7740                                         break;
7741                                 default:
7742                                         break;
7743                                 }
7744                         }
7745                         break;
7746                 /*  deprectated
7747                 case 6:
7748                         offset = fBACnetPropertyValue (tvb,pinfo,tree,offset);
7749                         break;
7750         */
7751
7752                 case 7: /* buffer-ready */
7753                         /* deprecated
7754                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) { 
7755                                 lastoffset = offset;
7756                                 switch (fTagNo(tvb, offset)) {
7757                                 case 0:
7758                                         offset = fUnsignedTag (tvb,tree,offset,"notification threshold");
7759                                         break;
7760                                 case 1:
7761                                         offset = fUnsignedTag (tvb,tree,offset,
7762                                                 "previous notification count: ");
7763                                         break;
7764                                 default:
7765                                         return offset;
7766                                 }
7767                         }
7768                         */
7769                         break;
7770                 case 8: /* change-of-life-safety */
7771                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7772                                 lastoffset = offset;
7773                                 switch (fTagNo(tvb, offset)) {
7774                                 case 0:
7775                                         offset = fTimeSpan (tvb, subtree, offset, "Time Delay");
7776                                         break;
7777                                 case 1:
7778                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7779                                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7780                                                 lastoffset = offset;
7781                                                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7782                                                 if (tag_is_closing(tag_info)) {
7783                                                         break;
7784                                                 }
7785                                                 offset = fEnumeratedTagSplit (tvb, subtree, offset,
7786                                                         "life safety alarm value: ", BACnetLifeSafetyState, 256);
7787                                         }
7788                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7789                                         break;
7790                                 case 2:
7791                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7792                                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7793                                                 lastoffset = offset;
7794                                                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
7795                                                 if (tag_is_closing(tag_info)) {
7796                                                         break;
7797                                                 }
7798                                                 offset = fEnumeratedTagSplit (tvb, subtree, offset,
7799                                                         "alarm value: ", BACnetLifeSafetyState, 256);
7800                                         }
7801                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7802                                         break;
7803                                 case 3:
7804                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7805                                         offset = fDeviceObjectPropertyReference (tvb, pinfo, subtree, offset);
7806                                         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7807                                         break;
7808                                 default:
7809                                         break;
7810                                 }
7811                         }
7812                         break;
7813                 case 9: /* extended */
7814                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7815                                 lastoffset = offset;
7816                                 switch (fTagNo(tvb, offset)) {
7817                                 case 0:
7818                                         offset = fVendorIdentifier (tvb, pinfo, tree, offset);
7819                                         break;
7820                                 case 1:
7821                                         offset = fUnsignedTag (tvb, tree, offset,
7822                                                 "extended-event-type: ");
7823                                         break;
7824                                 case 2: /* parameters */
7825                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
7826                                         offset = fApplicationTypes(tvb, pinfo, tree, offset, "parameters: ");
7827                                         offset = fDeviceObjectPropertyValue(tvb, pinfo, tree, offset);
7828                                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
7829                                 lastoffset = offset;
7830                                         break;
7831                                 default:
7832                                         break;
7833                                 }
7834                                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
7835                         }
7836                         break;
7837                 case 10: /* buffer-ready */
7838                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7839                                 lastoffset = offset;
7840                                 switch (fTagNo(tvb, offset)) {
7841                                 case 0:
7842                                         offset = fUnsignedTag (tvb, subtree, offset,
7843                                                 "notification-threshold: ");
7844                                         break;
7845                                 case 1:
7846                                         offset = fUnsignedTag (tvb, subtree, offset,
7847                                                 "previous-notification-count: ");
7848                                         break;
7849                                 default:
7850                                         break;
7851                                 }
7852                         }
7853                         break;
7854                 case 11: /* unsigned-range */
7855                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
7856                                 lastoffset = offset;
7857                                 switch (fTagNo(tvb, offset)) {
7858                                 case 0:
7859                                         offset = fTimeSpan (tvb, tree, offset, "Time Delay");
7860                                         break;
7861                                 case 1:
7862                                         offset = fUnsignedTag (tvb, tree, offset,
7863                                                 "low-limit: ");
7864                                         break;
7865                                 case 2:
7866                                         offset = fUnsignedTag (tvb, tree, offset,
7867                                                 "high-limit: ");
7868                                         break;
7869                                 default:
7870                                         break;
7871                                 }
7872                         }
7873                         break;
7874                         /* todo: add new event-parameter cases here */
7875                 default:
7876                         break;
7877                 }
7878         
7879         /* Closing tag for parameter choice */
7880         offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7881         return offset;
7882 }
7883
7884 static guint
7885 fEventLogRecord(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7886 {
7887         guint lastoffset = 0;
7888         guint8 tag_no, tag_info;
7889         guint32 lvt;
7890         proto_tree *subtree = tree;
7891         proto_item *tt;
7892
7893         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7894                 lastoffset = offset;
7895                 switch (fTagNo(tvb, offset)) {
7896                 case 0: /* timestamp */
7897                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7898                         offset = fDate (tvb,tree,offset,"Date: ");
7899                         offset = fTime (tvb,tree,offset,"Time: ");
7900                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7901                         break;
7902                 case 1: /* logDatum: don't loop, it's a CHOICE */
7903                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7904                         switch (fTagNo(tvb, offset)) {
7905                         case 0: /* logStatus */    /* Changed this to BitString per BACnet Spec. */
7906                             offset = fBitStringTagVS(tvb, tree, offset, "log status:", BACnetLogStatus);
7907                                 break;
7908                         case 1: /* todo: move this to new method fConfirmedEventNotificationRequestTag... */
7909                                 tt = proto_tree_add_text(tree, tvb, offset, 1, "notification: ");
7910                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
7911                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7912                                 offset = fConfirmedEventNotificationRequest(tvb, pinfo, subtree, offset);
7913                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
7914                                 break;
7915                         case 2:
7916                                 offset = fRealTag (tvb, tree, offset, "time-change: ");
7917                                 break;
7918                         default:
7919                                 return offset;
7920                         }
7921                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7922                         break;
7923                 default:
7924                         return offset;
7925                 }
7926                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
7927         }
7928         return offset;
7929 }
7930
7931 static guint
7932 fLogRecord (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
7933 {
7934         guint lastoffset = 0;
7935         guint8 tag_no, tag_info;
7936         guint32 lvt;
7937
7938         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
7939                 lastoffset = offset;
7940                 switch (fTagNo(tvb, offset)) {
7941                 case 0: /* timestamp */
7942                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7943                         offset = fDate (tvb,tree,offset,"Date: ");
7944                         offset = fTime (tvb,tree,offset,"Time: ");
7945                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7946                         break;
7947                 case 1: /* logDatum: don't loop, it's a CHOICE */
7948                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7949                         switch (fTagNo(tvb, offset)) {
7950                         case 0: /* logStatus */    /* Changed this to BitString per BACnet Spec. */
7951                             offset = fBitStringTagVS(tvb, tree, offset, "log status:", BACnetLogStatus);
7952                                 break;
7953                         case 1:
7954                                 offset = fBooleanTag (tvb, tree, offset, "boolean-value: ");
7955                                 break;
7956                         case 2:
7957                                 offset = fRealTag (tvb, tree, offset, "real value: ");
7958                                 break;
7959                         case 3:
7960                                 offset = fUnsignedTag (tvb, tree, offset, "enum value: ");
7961                                 break;
7962                         case 4:
7963                                 offset = fUnsignedTag (tvb, tree, offset, "unsigned value: ");
7964                                 break;
7965                         case 5:
7966                                 offset = fSignedTag (tvb, tree, offset, "signed value: ");
7967                                 break;
7968                         case 6:
7969                                 offset = fBitStringTag (tvb, tree, offset, "bitstring value: ");
7970                                 break;
7971                         case 7:
7972                                 offset = fNullTag(tvb, tree, offset, "null value: ");
7973                                 break;
7974                         case 8:
7975                                 offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7976                                 offset = fError (tvb, pinfo, tree, offset);
7977                                 offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7978                                 break;
7979                         case 9:
7980                                 offset = fRealTag (tvb, tree, offset, "time change: ");
7981                                 break;
7982                         case 10:        /* any Value */
7983                                 offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7984                                 offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset);
7985                                 offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7986                                 break;
7987                         default:
7988                                 return offset;
7989                         }
7990                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
7991                         break;
7992                 case 2:
7993                         /* Changed this to BitString per BACnet Spec. */
7994                         offset = fBitStringTagVS(tvb, tree, offset, "Status Flags:", BACnetStatusFlags);
7995                         break;
7996                 default:
7997                         return offset;
7998                 }
7999                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8000         }
8001         return offset;
8002 }
8003
8004 static guint
8005 fLogMultipleRecord (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8006 {
8007         guint lastoffset = 0;
8008         guint8 tag_no, tag_info;
8009         guint32 lvt;
8010
8011         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8012                 lastoffset = offset;
8013                 switch (fTagNo(tvb, offset)) {
8014                 case 0: /* timestamp */
8015                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8016                         offset = fDate (tvb,tree,offset,"Date: ");
8017                         offset = fTime (tvb,tree,offset,"Time: ");
8018                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8019                         break;
8020                 case 1: /* logData: don't loop, it's a CHOICE */
8021                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8022                         switch (fTagNo(tvb, offset)) {
8023                         case 0: /* logStatus */    /* Changed this to BitString per BACnet Spec. */
8024                             offset = fBitStringTagVS(tvb, tree, offset, "log status:", BACnetLogStatus);
8025                                 break;
8026                         case 1: /* log-data: SEQUENCE OF CHOICE */
8027                                 offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8028                                 while (tvb_reported_length_remaining(tvb, offset) && (offset != lastoffset)) {  /* exit loop if nothing happens inside */
8029                                         lastoffset = offset;
8030                                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8031                                         if (tag_is_closing(tag_info)) {
8032                                                 lastoffset = offset;
8033                                                 break;
8034                                         }
8035                                         switch (tag_no) {
8036                                                 case 0:
8037                                                         offset = fBooleanTag (tvb, tree, offset, "boolean-value: ");
8038                                                         break;
8039                                                 case 1:
8040                                                         offset = fRealTag (tvb, tree, offset, "real value: ");
8041                                                         break;
8042                                                 case 2:
8043                                                         offset = fUnsignedTag (tvb, tree, offset, "enum value: ");
8044                                                         break;
8045                                                 case 3:
8046                                                         offset = fUnsignedTag (tvb, tree, offset, "unsigned value: ");
8047                                                         break;
8048                                                 case 4:
8049                                                         offset = fSignedTag (tvb, tree, offset, "signed value: ");
8050                                                         break;
8051                                                 case 5:
8052                                                         offset = fBitStringTag (tvb, tree, offset, "bitstring value: ");
8053                                                         break;
8054                                                 case 6:
8055                                                         offset = fNullTag(tvb, tree, offset, "null value: ");
8056                                                         break;
8057                                                 case 7:
8058                                                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8059                                                         offset = fError (tvb, pinfo, tree, offset);
8060                                                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8061                                                         break;
8062                                                 case 8: /* any Value */
8063                                                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8064                                                         offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset);
8065                                                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8066                                                         break;
8067                                                 default: 
8068                                                         return offset;
8069                                         }
8070                                 }
8071                                 offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8072                                 break;
8073                         case 2:
8074                                 offset = fRealTag (tvb, tree, offset, "time-change: ");
8075                                 break;
8076                         default:
8077                                 return offset;
8078                         }
8079                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8080                         break;
8081                 default:
8082                         return offset;
8083                 }
8084                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8085         }
8086         return offset;
8087 }
8088
8089
8090 static guint
8091 fConfirmedEventNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8092 {
8093         guint lastoffset = 0;
8094         guint8 tag_no, tag_info;
8095         guint32 lvt;
8096
8097         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8098                 lastoffset = offset;
8099                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8100                 if (tag_is_closing(tag_info)) {
8101                         lastoffset = offset;
8102                         break;
8103                 }
8104
8105                 switch (tag_no) {
8106                 case 0: /* ProcessId */
8107                         offset = fProcessId (tvb,tree,offset);
8108                         break;
8109                 case 1: /* initiating ObjectId */
8110                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
8111                         break;
8112                 case 2: /* event ObjectId */
8113                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
8114                         break;
8115                 case 3: /* time stamp */
8116                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8117                         offset = fTimeStamp (tvb, tree, offset, NULL);
8118                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8119                         break;
8120                 case 4: /* notificationClass */
8121                         offset = fUnsignedTag (tvb, tree, offset, "Notification Class: ");
8122                         break;
8123                 case 5: /* Priority */
8124                         offset = fUnsignedTag (tvb, tree, offset, "Priority: ");
8125                         break;
8126                 case 6: /* EventType */
8127                         offset = fEnumeratedTagSplit (tvb, tree, offset,
8128                                 "Event Type: ", BACnetEventType, 64);
8129                         break;
8130                 case 7: /* messageText */
8131                         offset = fCharacterString (tvb, tree, offset, "message Text: ");
8132                         break;
8133                 case 8: /* NotifyType */
8134                         offset = fEnumeratedTag (tvb, tree, offset,
8135                                 "Notify Type: ", BACnetNotifyType);
8136                         break;
8137                 case 9: /* ackRequired */
8138                         offset = fBooleanTag (tvb, tree, offset, "ack Required: ");
8139                         break;
8140                 case 10: /* fromState */
8141                         offset = fEnumeratedTagSplit (tvb, tree, offset,
8142                                 "from State: ", BACnetEventState, 64);
8143                         break;
8144                 case 11: /* toState */
8145                         offset = fEnumeratedTagSplit (tvb, tree, offset,
8146                                 "to State: ", BACnetEventState, 64);
8147                         break;
8148                 case 12: /* NotificationParameters */
8149                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8150                         offset = fNotificationParameters (tvb, pinfo, tree, offset);
8151                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8152                         break;
8153                 default:
8154                         break;
8155                 }
8156                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8157         }
8158         return offset;
8159 }
8160
8161 static guint
8162 fUnconfirmedEventNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8163 {
8164         return fConfirmedEventNotificationRequest (tvb, pinfo, tree, offset);
8165 }
8166
8167 static guint
8168 fConfirmedCOVNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8169 {
8170         guint lastoffset = 0, len;
8171         guint8 tag_no, tag_info;
8172         guint32 lvt;
8173         proto_tree *subtree = tree;
8174         proto_item *tt;
8175
8176         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8177                 lastoffset = offset;
8178                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8179                 if (tag_is_closing(tag_info)) {
8180                         offset += len;
8181                         subtree = tree;
8182                         continue;
8183                 }
8184
8185                 switch (tag_no) {
8186                 case 0: /* ProcessId */
8187                         offset = fProcessId (tvb,tree,offset);
8188                         break;
8189                 case 1: /* initiating DeviceId */
8190                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
8191                         break;
8192                 case 2: /* monitored ObjectId */
8193                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
8194                         break;
8195                 case 3: /* time remaining */
8196                         offset = fTimeSpan (tvb, tree, offset, "Time remaining");
8197                         break;
8198                 case 4: /* List of Values */
8199                         if (tag_is_opening(tag_info)) {
8200                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "list of Values");
8201                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
8202                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
8203                                 offset = fBACnetPropertyValue (tvb, pinfo, subtree, offset);
8204                                 break;
8205                         }
8206                         FAULT;
8207                         break;
8208                 default:
8209                         return offset;
8210                 }
8211                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8212         }
8213         return offset;
8214 }
8215
8216 static guint
8217 fUnconfirmedCOVNotificationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8218 {
8219         return fConfirmedCOVNotificationRequest (tvb, pinfo, tree, offset);
8220 }
8221
8222 static guint
8223 fAcknowledgeAlarmRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8224 {
8225         guint lastoffset = 0;
8226         guint8 tag_no = 0, tag_info = 0;
8227         guint32 lvt = 0;
8228
8229         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8230                 lastoffset = offset;
8231                 switch (fTagNo(tvb, offset)) {
8232                 case 0: /* acknowledgingProcessId */
8233                         offset = fUnsignedTag (tvb, tree, offset, "acknowledging Process Id: ");
8234                         break;
8235                 case 1: /* eventObjectId */
8236                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
8237                         break;
8238                 case 2: /* eventStateAcknowledged */
8239                         offset = fEnumeratedTagSplit (tvb, tree, offset,
8240                                 "event State Acknowledged: ", BACnetEventState, 64);
8241                         break;
8242                 case 3: /* timeStamp */
8243                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
8244                         offset = fTimeStamp(tvb, tree, offset, NULL);
8245                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
8246                         break;
8247                 case 4: /* acknowledgementSource */
8248                         offset = fCharacterString (tvb, tree, offset, "acknowledgement Source: ");
8249                         break;
8250                 case 5: /* timeOfAcknowledgement */
8251                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
8252                         offset = fTimeStamp(tvb, tree, offset, "acknowledgement timestamp: ");
8253                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
8254                         break;
8255                 default:
8256                         return offset;
8257                 }
8258                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8259         }
8260         return offset;
8261 }
8262
8263 static guint
8264 fGetAlarmSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8265 {
8266         guint lastoffset = 0;
8267
8268         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8269                 lastoffset = offset;
8270                 offset = fApplicationTypes (tvb, pinfo, tree, offset, "Object Identifier: ");
8271                 offset = fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset,
8272                         "alarm State: ", BACnetEventState, 64);
8273                 offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset,
8274                         "acknowledged Transitions: ", BACnetEventTransitionBits);
8275                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8276         }
8277         return  offset;
8278 }
8279
8280 static guint
8281 fGetEnrollmentSummaryRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8282 {
8283         guint lastoffset = 0;
8284         guint8 tag_no, tag_info;
8285         guint32 lvt;
8286
8287         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8288                 lastoffset = offset;
8289                 switch (fTagNo(tvb, offset)) {
8290                 case 0: /* acknowledgmentFilter */
8291                         offset = fEnumeratedTag (tvb, tree, offset,
8292                                 "acknowledgment Filter: ", BACnetAcknowledgementFilter);
8293                         break;
8294                 case 1: /* eventObjectId - OPTIONAL */
8295                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8296                         offset = fRecipientProcess (tvb, pinfo, tree, offset);
8297                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8298                         break;
8299                 case 2: /* eventStateFilter */
8300                         offset = fEnumeratedTag (tvb, tree, offset,
8301                                 "event State Filter: ", BACnetEventStateFilter);
8302                         break;
8303                 case 3: /* eventTypeFilter - OPTIONAL */
8304                         offset = fEnumeratedTag (tvb, tree, offset,
8305                                 "event Type Filter: ", BACnetEventType);
8306                         break;
8307                 case 4: /* priorityFilter */
8308                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8309                         offset = fUnsignedTag (tvb, tree, offset, "min Priority: ");
8310                         offset = fUnsignedTag (tvb, tree, offset, "max Priority: ");
8311                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8312                         break;
8313                 case 5: /* notificationClassFilter - OPTIONAL */
8314                         offset = fUnsignedTag (tvb, tree, offset, "notification Class Filter: ");
8315                         break;
8316                 default:
8317                         return offset;
8318                 }
8319                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8320         }
8321         return offset;
8322 }
8323
8324 static guint
8325 fGetEnrollmentSummaryAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8326 {
8327         guint lastoffset = 0;
8328
8329         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8330                 lastoffset = offset;
8331                 offset = fApplicationTypes (tvb, pinfo, tree, offset, "Object Identifier: ");
8332                 offset = fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset,
8333                         "event Type: ", BACnetEventType, 64);
8334                 offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset,
8335                         "event State: ", BACnetEventState);
8336                 offset = fApplicationTypes (tvb, pinfo, tree, offset, "Priority: ");
8337                 offset = fApplicationTypes (tvb, pinfo, tree, offset, "Notification Class: ");
8338                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8339         }
8340
8341         return  offset;
8342 }
8343
8344 static guint
8345 fGetEventInformationRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8346 {
8347         if (tvb_reported_length_remaining(tvb, offset) > 0) {
8348                 if (fTagNo(tvb, offset) == 0) {
8349                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
8350                 }
8351         }
8352         return offset;
8353 }
8354
8355 static guint
8356 flistOfEventSummaries (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8357 {
8358         guint lastoffset = 0;
8359         guint8 tag_no, tag_info;
8360         guint32 lvt;
8361         proto_tree* subtree = tree;
8362         proto_item* ti = 0;
8363
8364         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8365                 lastoffset = offset;
8366                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8367                 /* we are finished here if we spot a closing tag */
8368                 if (tag_is_closing(tag_info)) {
8369                         break;
8370                 }
8371                 switch (tag_no) {
8372                 case 0: /* ObjectId */
8373                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
8374                         break;
8375                 case 1: /* eventState */
8376                         offset = fEnumeratedTag (tvb, tree, offset,
8377                                 "event State: ", BACnetEventState);
8378                         break;
8379                 case 2: /* acknowledgedTransitions */
8380                         offset = fBitStringTagVS (tvb, tree, offset,
8381                                 "acknowledged Transitions: ", BACnetEventTransitionBits);
8382                         break;
8383                 case 3: /* eventTimeStamps */
8384                         ti = proto_tree_add_text(tree, tvb, offset, lvt, "eventTimeStamps");
8385                         if (ti) {
8386                                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
8387                         }
8388                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
8389                         offset = fTimeStamp (tvb, subtree, offset,"TO-OFFNORMAL timestamp: ");
8390                         offset = fTimeStamp (tvb, subtree, offset,"TO-FAULT timestamp: ");
8391                         offset = fTimeStamp (tvb, subtree, offset,"TO-NORMAL timestamp: ");
8392                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
8393                         break;
8394                 case 4: /* notifyType */
8395                         offset = fEnumeratedTag (tvb, tree, offset,
8396                                 "Notify Type: ", BACnetNotifyType);
8397                         break;
8398                 case 5: /* eventEnable */
8399                         offset = fBitStringTagVS (tvb, tree, offset,
8400                                 "event Enable: ", BACnetEventTransitionBits);
8401                         break;
8402                 case 6: /* eventPriorities */
8403                         ti = proto_tree_add_text(tree, tvb, offset, lvt, "eventPriorities");
8404                         if (ti) {
8405                                 subtree = proto_item_add_subtree(ti, ett_bacapp_tag);
8406                         }
8407                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
8408                         offset = fUnsignedTag (tvb, subtree, offset, "TO-OFFNORMAL Priority: ");
8409                         offset = fUnsignedTag (tvb, subtree, offset, "TO-FAULT Priority: ");
8410                         offset = fUnsignedTag (tvb, subtree, offset, "TO-NORMAL Priority: ");
8411                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
8412                         break;
8413                 default:
8414                         return offset;
8415                 }
8416                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8417         }
8418         return offset;
8419 }
8420
8421 static guint
8422 fLOPR (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8423 {
8424         guint lastoffset = 0;
8425         guint8 tag_no, tag_info;
8426         guint32 lvt;
8427
8428         col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
8429         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8430                 lastoffset = offset;
8431                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8432                 /* we are finished here if we spot a closing tag */
8433                 if (tag_is_closing(tag_info)) {
8434                         break;
8435                 }
8436                 offset = fDeviceObjectPropertyReference(tvb, pinfo, tree, offset);
8437                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8438         }
8439         return offset;
8440 }
8441
8442 static guint
8443 fGetEventInformationACK (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8444 {
8445         guint lastoffset = 0;
8446         guint8 tag_no, tag_info;
8447         guint32 lvt;
8448
8449         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8450                 lastoffset = offset;
8451                 switch (fTagNo(tvb, offset)) {
8452                 case 0: /* listOfEventSummaries */
8453                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8454                         offset = flistOfEventSummaries (tvb, pinfo, tree, offset);
8455                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
8456                         break;
8457                 case 1: /* moreEvents */
8458                         offset = fBooleanTag (tvb, tree, offset, "more Events: ");
8459                         break;
8460                 default:
8461                         return offset;
8462                 }
8463                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8464         }
8465         return offset;
8466 }
8467
8468 static guint
8469 fAddListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8470 {
8471         guint lastoffset = 0, len;
8472         guint8 tag_no, tag_info;
8473         guint32 lvt;
8474         proto_tree *subtree = tree;
8475         proto_item *tt;
8476
8477         col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
8478
8479         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8480                 lastoffset = offset;
8481                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8482                 if (tag_is_closing(tag_info)) {
8483                         offset += len;
8484                         subtree = tree;
8485                         continue;
8486                 }
8487
8488                 switch (tag_no) {
8489                 case 0: /* ObjectId */
8490                         offset = fBACnetObjectPropertyReference (tvb, pinfo, subtree, offset);
8491                         break;
8492                 case 3: /* listOfElements */
8493                         if (tag_is_opening(tag_info)) {
8494                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfElements");
8495                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
8496                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
8497                                 offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset);
8498                                 break;
8499                         }
8500                         FAULT;
8501                         break;
8502                 default:
8503                         return offset;
8504                 }
8505                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8506         }
8507         return offset;
8508 }
8509
8510 static guint
8511 fDeleteObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8512 {
8513         return fObjectIdentifier (tvb, pinfo, tree, offset);
8514 }
8515
8516 static guint
8517 fDeviceCommunicationControlRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
8518 {
8519         guint lastoffset = 0;
8520
8521         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8522                 lastoffset = offset;
8523
8524                 switch (fTagNo(tvb, offset)) {
8525                 case 0: /* timeDuration */
8526                         offset = fUnsignedTag (tvb,tree,offset,"time Duration: ");
8527                         break;
8528                 case 1: /* enable-disable */
8529                         offset = fEnumeratedTag (tvb, tree, offset, "enable-disable: ",
8530                                 BACnetEnableDisable);
8531                         break;
8532                 case 2: /* password - OPTIONAL */
8533                         offset = fCharacterString (tvb, tree, offset, "Password: ");
8534                         break;
8535                 default:
8536                         return offset;
8537                 }
8538                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8539         }
8540         return offset;
8541 }
8542
8543 static guint
8544 fReinitializeDeviceRequest(tvbuff_t *tvb, proto_tree *tree, guint offset)
8545 {
8546         guint lastoffset = 0;
8547
8548         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8549                 lastoffset = offset;
8550
8551                 switch (fTagNo(tvb, offset)) {
8552                 case 0: /* reinitializedStateOfDevice */
8553                         offset = fEnumeratedTag (tvb, tree, offset,
8554                                 "reinitialized State Of Device: ",
8555                                 BACnetReinitializedStateOfDevice);
8556                         break;
8557                 case 1: /* password - OPTIONAL */
8558                         offset = fCharacterString (tvb, tree, offset, "Password: ");
8559                         break;
8560                 default:
8561                         return offset;
8562                 }
8563                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8564         }
8565         return offset;
8566 }
8567
8568 static guint
8569 fVtOpenRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8570 {
8571         offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset,
8572                 "vtClass: ", BACnetVTClass);
8573         return fApplicationTypes (tvb, pinfo, tree,offset,"local VT Session ID: ");
8574 }
8575
8576 static guint
8577 fVtOpenAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8578 {
8579         return fApplicationTypes (tvb, pinfo, tree,offset,"remote VT Session ID: ");
8580 }
8581
8582 static guint
8583 fVtCloseRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8584 {
8585         guint lastoffset = 0;
8586
8587         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8588                 lastoffset = offset;
8589                 offset= fApplicationTypes (tvb, pinfo, tree,offset,"remote VT Session ID: ");
8590                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8591         }
8592         return offset;
8593 }
8594
8595 static guint
8596 fVtDataRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8597 {
8598         offset= fApplicationTypes (tvb, pinfo, tree,offset,"VT Session ID: ");
8599         offset = fApplicationTypes (tvb, pinfo, tree, offset, "VT New Data: ");
8600         return fApplicationTypes (tvb, pinfo, tree,offset,"VT Data Flag: ");;
8601 }
8602
8603 static guint
8604 fVtDataAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
8605 {
8606         guint lastoffset = 0;
8607
8608         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8609                 lastoffset = offset;
8610
8611                 switch (fTagNo(tvb,offset)) {
8612                 case 0: /* BOOLEAN */
8613                         offset = fBooleanTag (tvb, tree, offset, "all New Data Accepted: ");
8614                         break;
8615                 case 1: /* Unsigned OPTIONAL */
8616                         offset = fUnsignedTag (tvb, tree, offset, "accepted Octet Count: ");
8617                         break;
8618                 default:
8619                         return offset;
8620                 }
8621                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8622         }
8623         return offset;
8624 }
8625
8626 static guint
8627 fAuthenticateRequest (tvbuff_t *tvb, proto_tree *tree, guint offset)
8628 {
8629         guint lastoffset = 0;
8630
8631         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8632                 lastoffset = offset;
8633
8634                 switch (fTagNo(tvb,offset)) {
8635                 case 0: /* Unsigned32 */
8636                         offset = fUnsignedTag (tvb, tree, offset, "pseudo Random Number: ");
8637                         break;
8638                 case 1: /* expected Invoke ID Unsigned8 OPTIONAL */
8639                         proto_tree_add_item(tree, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN);
8640                         break;
8641                 case 2: /* Chararacter String OPTIONAL */
8642                         offset = fCharacterString (tvb, tree, offset, "operator Name: ");
8643                         break;
8644                 case 3: /* Chararacter String OPTIONAL */
8645                         offset = fCharacterString (tvb, tree, offset, "operator Password: ");
8646                         break;
8647                 case 4: /* Boolean OPTIONAL */
8648                         offset = fBooleanTag (tvb, tree, offset, "start Encyphered Session: ");
8649                         break;
8650                 default:
8651                         return offset;
8652                 }
8653                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8654         }
8655         return offset;
8656 }
8657
8658 static guint
8659 fAuthenticateAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8660 {
8661         return fApplicationTypes (tvb, pinfo, tree, offset, "modified Random Number: ");
8662 }
8663
8664 static guint
8665 fRequestKeyRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8666 {
8667         offset = fObjectIdentifier (tvb, pinfo, tree, offset); /* Requesting Device Identifier */
8668         offset = fAddress (tvb, tree, offset);
8669         offset = fObjectIdentifier (tvb, pinfo, tree, offset); /* Remote Device Identifier */
8670         return fAddress (tvb, tree, offset);
8671 }
8672
8673 static guint
8674 fRemoveListElementRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8675 {
8676         /* Same as AddListElement request after service choice */
8677         return fAddListElementRequest(tvb, pinfo, tree, offset);
8678 }
8679
8680 static guint
8681 fReadPropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8682 {
8683         return fBACnetObjectPropertyReference(tvb, pinfo, tree, offset);
8684 }
8685
8686 static guint
8687 fReadPropertyAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8688 {
8689         guint lastoffset = 0, len;
8690         guint8 tag_no, tag_info;
8691         guint32 lvt;
8692         proto_tree *subtree = tree;
8693
8694         /* set the optional global properties to indicate not-used */
8695         propertyArrayIndex = -1;
8696         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8697                 lastoffset = offset;
8698                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8699                 if (tag_is_closing(tag_info)) {
8700                         offset += len;
8701                         subtree = tree;
8702                         continue;
8703                 }
8704                 switch (tag_no) {
8705                 case 0: /* objectIdentifier */
8706                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
8707                         break;
8708                 case 1: /* propertyIdentifier */
8709                         offset = fPropertyIdentifier (tvb, pinfo, subtree, offset);
8710                         break;
8711                 case 2: /* propertyArrayIndex */
8712                         offset = fPropertyArrayIndex (tvb, subtree, offset);
8713                         break;
8714                 case 3: /* propertyValue */
8715                         offset = fPropertyValue (tvb, pinfo, subtree, offset, tag_info);
8716                         break;
8717                 default:
8718                         break;
8719                 }
8720                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8721         }
8722         return offset;
8723 }
8724
8725 static guint
8726 fWritePropertyRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8727 {
8728         guint lastoffset = 0;
8729         guint8 tag_no, tag_info;
8730         guint32 lvt;
8731         proto_tree *subtree = tree;
8732
8733         /* set the optional global properties to indicate not-used */
8734         propertyArrayIndex = -1;
8735         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8736                 lastoffset = offset;
8737                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8738                 /* quit loop if we spot a closing tag */
8739                 if (tag_is_closing(tag_info)) {
8740                         subtree = tree;
8741                         break;
8742                 }
8743
8744                 switch (tag_no) {
8745                 case 0: /* objectIdentifier */
8746                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
8747                         break;
8748                 case 1: /* propertyIdentifier */
8749                         offset = fPropertyIdentifier (tvb, pinfo, subtree, offset);
8750                         break;
8751                 case 2: /* propertyArrayIndex */
8752                         offset = fPropertyArrayIndex (tvb, subtree, offset);
8753                         break;
8754                 case 3: /* propertyValue */
8755                         offset = fPropertyValue (tvb, pinfo, subtree, offset, tag_info);
8756                         break;
8757                 case 4: /* Priority (only used for write) */
8758                         offset = fUnsignedTag (tvb, subtree, offset, "Priority: ");
8759                         break;
8760                 default:
8761                         return offset;
8762                 }
8763                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8764         }
8765         return offset;
8766 }
8767
8768 static guint
8769 fWriteAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset)
8770 {
8771         guint lastoffset = 0, len;
8772         guint8 tag_no, tag_info;
8773         guint32 lvt;
8774
8775         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8776                 lastoffset = offset;
8777                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8778                 /* maybe a listOfwriteAccessSpecifications if we spot a closing tag */
8779                 if (tag_is_closing(tag_info)) {
8780                         offset += len;
8781                         continue;
8782                 }
8783
8784                 switch (tag_no) {
8785                 case 0: /* objectIdentifier */
8786                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
8787                         break;
8788                 case 1: /* listOfPropertyValues */
8789                         if (tag_is_opening(tag_info)) {
8790                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
8791                                 offset = fBACnetPropertyValue (tvb, pinfo, subtree, offset);
8792                                 break;
8793                         }
8794                         FAULT;
8795                         break;
8796                 default:
8797                         return offset;
8798                 }
8799                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8800         }
8801         return offset;
8802 }
8803
8804 static guint
8805 fWritePropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8806 {
8807         if (offset >= tvb_reported_length(tvb))
8808                 return offset;
8809
8810         col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
8811         return fWriteAccessSpecification (tvb, pinfo, tree, offset);
8812 }
8813
8814 static guint
8815 fPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 tagoffset, guint8 list)
8816 {
8817         guint lastoffset = 0;
8818         guint8 tag_no, tag_info;
8819         guint32 lvt;
8820
8821         /* set the optional global properties to indicate not-used */
8822         propertyArrayIndex = -1;
8823         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8824                 lastoffset = offset;
8825                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8826                 if (tag_is_closing(tag_info)) { /* closing Tag, but not for me */
8827                         return offset;
8828                 } else if (tag_is_opening(tag_info)) { /* opening Tag, but not for me */
8829                         return offset;
8830                 }
8831                 switch (tag_no-tagoffset) {
8832                 case 0: /* PropertyIdentifier */
8833                         offset = fPropertyIdentifier (tvb, pinfo, tree, offset);
8834                         break;
8835                 case 1: /* propertyArrayIndex */
8836                         offset = fPropertyArrayIndex (tvb, tree, offset);
8837                         if (list != 0) break; /* Continue decoding if this may be a list */
8838                 default:
8839                         lastoffset = offset; /* Set loop end condition */
8840                         break;
8841                 }
8842                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8843         }
8844         return offset;
8845 }
8846
8847 static guint
8848 fBACnetPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint8 list)
8849 {
8850         col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
8851         return fPropertyReference(tvb, pinfo, tree, offset, 0, list);
8852 }
8853
8854 static guint
8855 fBACnetObjectPropertyReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8856 {
8857         guint lastoffset = 0;
8858
8859         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8860                 lastoffset = offset;
8861
8862                 switch (fTagNo(tvb,offset)) {
8863                 case 0: /* ObjectIdentifier */
8864                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
8865                         break;
8866                 case 1: /* PropertyIdentifier and propertyArrayIndex */
8867                         offset = fPropertyReference (tvb, pinfo, tree, offset, 1, 0);
8868                         col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
8869                 default:
8870                         lastoffset = offset; /* Set loop end condition */
8871                         break;
8872                 }
8873                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8874         }
8875         return offset;
8876 }
8877
8878 #if 0
8879 static guint
8880 fObjectPropertyValue (tvbuff_t *tvb, proto_tree *tree, guint offset)
8881 {
8882         guint lastoffset = 0;
8883         guint8 tag_no, tag_info;
8884         guint32 lvt;
8885         proto_tree* subtree = tree;
8886         proto_item* tt;
8887
8888         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {  /* exit loop if nothing happens inside */
8889                 lastoffset = offset;
8890                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8891                 if (tag_is_closing(tag_info)) {
8892                         offset += fTagHeaderTree (tvb, subtree, offset,
8893                                 &tag_no, &tag_info, &lvt);
8894                         continue;
8895                 }
8896                 switch (tag_no) {
8897                 case 0: /* ObjectIdentifier */
8898                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
8899                         break;
8900                 case 1: /* PropertyIdentifier */
8901                         offset = fPropertyIdentifier (tvb, pinfo, subtree, offset);
8902                         break;
8903                 case 2: /* propertyArrayIndex */
8904                         offset = fUnsignedTag (tvb, subtree, offset, "property Array Index: ");
8905                         break;
8906                 case 3:  /* Value */
8907                         offset = fPropertyValue (tvb, subtree, offset, tag_info);
8908                         break;
8909                 case 4:  /* Priority */
8910                         offset = fUnsignedTag (tvb, subtree, offset, "Priority: ");
8911                         break;
8912                 default:
8913                         break;
8914                 }
8915         }
8916         return offset;
8917 }
8918 #endif
8919
8920 static guint
8921 fPriorityArray (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8922 {
8923         char i = 1, ar[256];
8924         guint lastoffset = 0;
8925
8926         if (propertyArrayIndex > 0) {
8927                 /* BACnetARRAY index 0 refers to the length
8928                 of the array, not the elements of the array.
8929                 BACnetARRAY index -1 is our internal flag that
8930                 the optional index was not used.
8931                 BACnetARRAY refers to this as all elements of the array.
8932                 If the optional index is specified for a BACnetARRAY,
8933                 then that specific array element is referenced. */
8934                 i = propertyArrayIndex;
8935         }
8936         while (tvb_reported_length_remaining(tvb, offset)) {
8937                 /* exit loop if nothing happens inside */
8938                 lastoffset = offset;
8939                 g_snprintf (ar, sizeof(ar), "%s[%d]: ",
8940                         val_to_split_str(87 , 512,
8941                                 BACnetPropertyIdentifier,
8942                                 ASHRAE_Reserved_Fmt,
8943                                 Vendor_Proprietary_Fmt),
8944                         i++);
8945                 /* DMR Should be fAbstractNSyntax, but that's where we came from! */
8946                 offset = fApplicationTypes(tvb, pinfo, tree, offset, ar);
8947                 /* there are only 16 priority array elements */
8948                 if (i > 16) {
8949                         break;
8950                 }
8951                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8952         }
8953
8954         return offset;
8955 }
8956
8957 static guint
8958 fDeviceObjectReference (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
8959 {
8960         guint lastoffset = 0;
8961
8962         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8963                 lastoffset = offset;
8964
8965                 switch (fTagNo(tvb,offset)) {
8966                 case 0: /* deviceIdentifier - OPTIONAL */
8967                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
8968                         break;
8969                 case 1: /* ObjectIdentifier */
8970                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
8971                         break;
8972                 default:
8973                         return offset;
8974                 }
8975                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
8976         }
8977         return offset;
8978 }
8979
8980 static guint
8981 fSpecialEvent (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset)
8982 {
8983         guint8 tag_no, tag_info;
8984         guint32 lvt;
8985         guint lastoffset = 0, len;
8986     gboolean closing_found = FALSE;  /* tracks when we are done decoding the fSpecialEvent entries */
8987
8988         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
8989                 lastoffset = offset;
8990                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
8991                 /* maybe a SEQUENCE of SpecialEvents if we spot a closing tag */
8992                 if (tag_is_closing(tag_info)) {
8993                         /* if we find 2 closing tags in succession we need to exit without incrementing the offset again */
8994                         /* This handles the special case where we have a special event entry in an RPM-ACK msg           */
8995                         if ( closing_found == TRUE )
8996                                 break;
8997                         offset += len;
8998                         closing_found = TRUE;
8999                         continue;
9000                 }
9001
9002                 switch (tag_no) {
9003                 case 0: /* calendarEntry */
9004                         if (tag_is_opening(tag_info)) {
9005                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9006                                 offset = fCalendarEntry (tvb, subtree, offset);
9007                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9008                         }
9009                         break;
9010                 case 1: /* calendarReference */
9011                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
9012                         break;
9013                 case 2: /* list of BACnetTimeValue */
9014                         if (tag_is_opening(tag_info)) {
9015                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9016                                 offset = fTimeValue (tvb, pinfo, subtree, offset);
9017                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9018                                 break;
9019                         }
9020                         FAULT;
9021                         break;
9022                 case 3: /* eventPriority */
9023                         offset = fUnsignedTag (tvb, subtree, offset, "event priority: ");
9024                         break;
9025                 default:
9026                         return offset;
9027                 }
9028                 closing_found = FALSE; /* reset our closing tag status, we processed another open tag */
9029                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9030         }
9031         return offset;
9032 }
9033
9034 static guint
9035 fSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9036 {
9037         guint lastoffset = 0, len;
9038         guint8 tag_no, tag_info;
9039         guint32 lvt;
9040
9041         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
9042                 lastoffset = offset;
9043                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9044                 /* maybe a listOfSelectionCriteria if we spot a closing tag */
9045                 if (tag_is_closing(tag_info)) {
9046                         offset += len;
9047                         continue;
9048                 }
9049
9050                 switch (fTagNo(tvb,offset)) {
9051                 case 0: /* propertyIdentifier */
9052                         offset = fPropertyIdentifier (tvb, pinfo, tree, offset);
9053                         break;
9054                 case 1: /* propertyArrayIndex */
9055                         offset = fPropertyArrayIndex (tvb, tree, offset);
9056                         break;
9057                 case 2: /* relationSpecifier */
9058                         offset = fEnumeratedTag (tvb, tree, offset,
9059                                 "relation Specifier: ", BACnetRelationSpecifier);
9060                         break;
9061                 case 3: /* comparisonValue */
9062                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
9063                         offset = fAbstractSyntaxNType (tvb, pinfo, tree, offset);
9064                         offset += fTagHeaderTree (tvb, tree, offset, &tag_no, &tag_info, &lvt);
9065                         break;
9066                 default:
9067                         return offset;
9068                 }
9069                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9070         }
9071         return offset;
9072 }
9073
9074 static guint
9075 fObjectSelectionCriteria (tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset)
9076 {
9077         guint lastoffset = 0;
9078         guint8 tag_no, tag_info;
9079         guint32 lvt;
9080
9081         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
9082                 lastoffset = offset;
9083                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9084                 /* quit loop if we spot a closing tag */
9085                 if (tag_is_closing(tag_info)) {
9086                         break;
9087                 }
9088
9089                 switch (tag_no) {
9090                 case 0: /* selectionLogic */
9091                         offset = fEnumeratedTag (tvb, subtree, offset,
9092                                 "selection Logic: ", BACnetSelectionLogic);
9093                         break;
9094                 case 1: /* listOfSelectionCriteria */
9095                         if (tag_is_opening(tag_info)) {
9096                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9097                                 offset = fSelectionCriteria (tvb, pinfo, subtree, offset);
9098                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9099                                 break;
9100                         }
9101                         FAULT;
9102                         break;
9103                 default:
9104                         return offset;
9105                 }
9106                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9107         }
9108         return offset;
9109 }
9110
9111
9112 static guint
9113 fReadPropertyConditionalRequest(tvbuff_t *tvb, packet_info* pinfo, proto_tree *subtree, guint offset)
9114 {
9115         guint lastoffset = 0;
9116         guint8 tag_no, tag_info;
9117         guint32 lvt;
9118
9119         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
9120                 lastoffset = offset;
9121                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9122
9123                 if (tag_is_opening(tag_info) && tag_no < 2) {
9124                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9125                         switch (tag_no) {
9126                         case 0: /* objectSelectionCriteria */
9127                                 offset = fObjectSelectionCriteria (tvb, pinfo, subtree, offset);
9128                                 break;
9129                         case 1: /* listOfPropertyReferences */
9130                                 offset = fBACnetPropertyReference (tvb, pinfo, subtree, offset, 1);
9131                                 break;
9132                         default:
9133                                 return offset;
9134                         }
9135                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9136                 }
9137                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9138         }
9139         return offset;
9140 }
9141
9142 static guint
9143 fReadAccessSpecification (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9144 {
9145         guint lastoffset = 0;
9146         guint8 tag_no, tag_info;
9147         guint32 lvt;
9148         proto_item *tt;
9149         proto_tree *subtree = tree;
9150
9151         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
9152                 lastoffset = offset;
9153                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9154                 switch (tag_no) {
9155                 case 0: /* objectIdentifier */
9156                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
9157                         break;
9158                 case 1: /* listOfPropertyReferences */
9159                         if (tag_is_opening(tag_info)) {
9160                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "listOfPropertyReferences");
9161                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
9162                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9163                                 offset = fBACnetPropertyReference (tvb, pinfo, subtree, offset, 1);
9164                         } else if (tag_is_closing(tag_info)) {
9165                                 offset += fTagHeaderTree (tvb, subtree, offset,
9166                                         &tag_no, &tag_info, &lvt);
9167                                 subtree = tree;
9168                         } else {
9169                                 /* error condition: let caller handle */
9170                                 return offset;
9171                         }
9172                         break;
9173                 default:
9174                         return offset;
9175                 }
9176                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9177         }
9178         return offset;
9179 }
9180
9181 static guint
9182 fReadAccessResult (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9183 {
9184         guint lastoffset = 0, len;
9185         guint8 tag_no;
9186         guint8 tag_info;
9187         guint32 lvt;
9188         proto_tree *subtree = tree;
9189         proto_item *tt;
9190
9191         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
9192                 lastoffset = offset;
9193                 len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9194                 /* maybe a listOfReadAccessResults if we spot a closing tag here */
9195                 if (tag_is_closing(tag_info)) {
9196                         offset += len;
9197                         if ((tag_no == 4 || tag_no == 5) && (subtree != tree)) subtree = subtree->parent; /* Value and error have extra subtree */
9198                         continue;
9199                 }
9200
9201                 switch (tag_no) {
9202                 case 0: /* objectSpecifier */
9203                         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
9204                         break;
9205                 case 1: /* list of Results */
9206                         if (tag_is_opening(tag_info)) {
9207                                 tt = proto_tree_add_text(tree, tvb, offset, 1, "listOfResults");
9208                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
9209                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9210                                 break;
9211                         }
9212                         FAULT;
9213                         break;
9214                 case 2: /* propertyIdentifier */
9215                         offset = fPropertyIdentifierValue(tvb, pinfo, subtree, offset, 2);
9216                         break;
9217                 case 5: /* propertyAccessError */
9218                         if (tag_is_opening(tag_info)) {
9219                                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "propertyAccessError");
9220                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
9221                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9222                                 /* Error Code follows */
9223                                 offset = fError(tvb, pinfo, subtree, offset);
9224                                 break;
9225                         }
9226                         FAULT;
9227                         break;
9228                 default:
9229                         return offset;
9230                 }
9231                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9232         }
9233         return offset;
9234 }
9235
9236
9237 static guint
9238 fReadPropertyConditionalAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9239 {
9240         /* listOfReadAccessResults */
9241         return fReadAccessResult (tvb, pinfo, tree, offset);
9242 }
9243
9244
9245 static guint
9246 fCreateObjectRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset)
9247 {
9248         guint lastoffset = 0;
9249         guint8 tag_no, tag_info;
9250         guint32 lvt;
9251
9252         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
9253                 lastoffset = offset;
9254                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9255
9256                 if (tag_no < 2) {
9257                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9258                         switch (tag_no) {
9259                         case 0: /* objectSpecifier */
9260                                 switch (fTagNo(tvb, offset)) { /* choice of objectType or objectIdentifier */
9261                                 case 0: /* objectType */
9262                                         offset = fEnumeratedTagSplit (tvb, subtree, offset, "Object Type: ", BACnetObjectType, 128);
9263                                         break;
9264                                 case 1: /* objectIdentifier */
9265                                         offset = fObjectIdentifier (tvb, pinfo, subtree, offset);
9266                                         break;
9267                                 default:
9268                                         break;
9269                                 }
9270                                 break;
9271                         case 1: /* propertyValue */
9272                                 if (tag_is_opening(tag_info)) {
9273                                         offset = fBACnetPropertyValue (tvb, pinfo, subtree, offset);
9274                                         break;
9275                                 }
9276                                 FAULT;
9277                                 break;
9278                         default:
9279                                 break;
9280                         }
9281                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9282                 }
9283                 if (offset == lastoffset) break;    /* nothing happened, exit loop */
9284         }
9285         return offset;
9286 }
9287
9288 static guint
9289 fCreateObjectAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9290 {
9291         return fObjectIdentifier (tvb, pinfo, tree, offset);
9292 }
9293
9294 static guint
9295 fReadRangeRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9296 {
9297         guint8 tag_no, tag_info;
9298         guint32 lvt;
9299         proto_tree *subtree = tree;
9300         proto_item *tt;
9301
9302         offset = fBACnetObjectPropertyReference(tvb, pinfo, subtree, offset);
9303
9304         if (tvb_reported_length_remaining(tvb, offset) > 0) {
9305                 /* optional range choice */
9306                 fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9307                 if (tag_is_opening(tag_info)) {
9308                         tt = proto_tree_add_text(subtree, tvb, offset, 1, "%s", val_to_str(tag_no, BACnetReadRangeOptions, "unknown range option"));
9309                         subtree = proto_item_add_subtree(tt, ett_bacapp_value);
9310                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9311                         switch (tag_no) {
9312                         case 3: /* range byPosition */
9313                         case 6: /* range bySequenceNumber, 2004 spec */
9314                                 offset = fApplicationTypes (tvb, pinfo, subtree, offset, "reference Index: ");
9315                                 offset = fApplicationTypes (tvb, pinfo, subtree, offset, "reference Count: ");
9316                                 break;
9317                         case 4: /* range byTime - deprecated in 2004 */
9318                         case 7: /* 2004 spec */
9319                                 offset = fDateTime(tvb, subtree, offset, "reference Date/Time: ");
9320                                 offset = fApplicationTypes (tvb, pinfo, subtree, offset, "reference Count: ");
9321                                 break;
9322                         case 5: /* range timeRange - deprecated in 2004 */
9323                                 offset = fDateTime(tvb, subtree, offset, "beginning Time: ");
9324                                 offset = fDateTime(tvb, subtree, offset, "ending Time: ");
9325                                 break;
9326                         default:
9327                                 break;
9328                         }
9329                         offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9330                 }
9331         }
9332         return offset;
9333 }
9334
9335 static guint
9336 fReadRangeAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9337 {
9338         guint8 tag_no, tag_info;
9339         guint32 lvt;
9340         proto_tree *subtree = tree;
9341         proto_item *tt;
9342
9343         /* set the optional global properties to indicate not-used */
9344         propertyArrayIndex = -1;
9345         /* objectIdentifier, propertyIdentifier, and
9346            OPTIONAL propertyArrayIndex */
9347         offset = fBACnetObjectPropertyReference(tvb, pinfo, subtree, offset);
9348         /* resultFlags => BACnetResultFlags ::= BIT STRING */
9349         offset = fBitStringTagVS (tvb, tree, offset,
9350                 "resultFlags: ",
9351                 BACnetResultFlags);
9352         /* itemCount */
9353         offset = fUnsignedTag (tvb, subtree, offset, "item Count: ");
9354         /* itemData */
9355         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9356         if (tag_is_opening(tag_info)) {
9357                 col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
9358                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "itemData");
9359                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
9360                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9361                 offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset);
9362                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9363         }
9364         /* firstSequenceNumber - OPTIONAL */
9365         if (tvb_reported_length_remaining(tvb, offset) > 0) {
9366                 offset = fUnsignedTag (tvb, subtree, offset, "first Sequence Number: ");
9367         }
9368
9369         return offset;
9370 }
9371
9372 static guint
9373 fAccessMethod(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9374 {
9375         guint lastoffset = 0;
9376         guint32 lvt;
9377         guint8 tag_no, tag_info;
9378         proto_item* tt;
9379         proto_tree* subtree = NULL;
9380
9381         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9382
9383         if (tag_is_opening(tag_info)) {
9384                 tt = proto_tree_add_text(tree, tvb, offset, 1, "%s", val_to_str(tag_no, BACnetFileAccessOption, "invalid access method"));
9385                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
9386                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9387                 offset = fApplicationTypes (tvb, pinfo, subtree, offset, val_to_str(tag_no, BACnetFileStartOption, "invalid option"));
9388                 offset = fApplicationTypes (tvb, pinfo, subtree, offset, val_to_str(tag_no, BACnetFileWriteInfo, "unknown option"));
9389
9390                 if (tag_no == 1) {
9391                         while ((tvb_reported_length_remaining(tvb, offset) > 0)&&(offset>lastoffset)) {
9392                                 /* exit loop if nothing happens inside */
9393                                 lastoffset = offset;
9394                                 offset = fApplicationTypes (tvb, pinfo, subtree, offset, "Record Data: ");
9395                         }
9396                 }
9397
9398                 if ((bacapp_flags & BACAPP_MORE_SEGMENTS) == 0) {
9399                         /* More Flag is not set, so we can look for closing tag in this segment */
9400                         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9401                         if (tag_is_closing(tag_info)) {
9402                                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9403                         }
9404                 }
9405         }
9406         return offset;
9407 }
9408
9409 static guint
9410 fAtomicReadFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9411 {
9412         guint8 tag_no, tag_info;
9413         guint32 lvt;
9414         proto_tree *subtree = tree;
9415         proto_item *tt;
9416
9417         offset = fObjectIdentifier (tvb, pinfo, tree, offset);
9418
9419         fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9420
9421         if (tag_is_opening(tag_info)) {
9422                 tt = proto_tree_add_text(subtree, tvb, offset, 1, "%s", val_to_str(tag_no, BACnetFileAccessOption, "unknown access method"));
9423                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
9424                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9425                 offset = fSignedTag (tvb, subtree, offset, val_to_str(tag_no, BACnetFileStartOption, "unknown option"));
9426                 offset = fUnsignedTag (tvb, subtree, offset, val_to_str(tag_no, BACnetFileRequestCount, "unknown option"));
9427                 offset += fTagHeaderTree (tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9428         }
9429         return offset;
9430 }
9431
9432 static guint
9433 fAtomicWriteFileRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9434 {
9435
9436         offset = fObjectIdentifier (tvb, pinfo, tree, offset); /* file Identifier */
9437         offset = fAccessMethod(tvb, pinfo, tree, offset);
9438
9439         return offset;
9440 }
9441
9442 static guint
9443 fAtomicWriteFileAck (tvbuff_t *tvb, proto_tree *tree, guint offset)
9444 {
9445         guint tag_no = fTagNo(tvb, offset);
9446         return fSignedTag (tvb, tree, offset, val_to_str(tag_no, BACnetFileStartOption, "unknown option"));
9447 }
9448
9449 static guint
9450 fAtomicReadFileAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9451 {
9452         offset = fApplicationTypes (tvb, pinfo, tree, offset, "End Of File: ");
9453         offset = fAccessMethod(tvb,pinfo, tree, offset);
9454
9455         return offset;
9456 }
9457
9458 static guint
9459 fReadPropertyMultipleRequest(tvbuff_t *tvb, packet_info *pinfo, proto_tree *subtree, guint offset)
9460 {
9461         col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
9462         return fReadAccessSpecification (tvb,pinfo,subtree,offset);
9463 }
9464
9465 static guint
9466 fReadPropertyMultipleAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9467 {
9468         col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
9469         return fReadAccessResult (tvb,pinfo,tree,offset);
9470 }
9471
9472 static guint
9473 fConfirmedServiceRequest (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice)
9474 {
9475         if (tvb_reported_length_remaining(tvb,offset) <= 0)
9476                 return offset;
9477
9478         switch (service_choice) {
9479         case 0: /* acknowledgeAlarm */
9480                 offset = fAcknowledgeAlarmRequest (tvb, pinfo, tree, offset);
9481                 break;
9482         case 1: /* confirmedCOVNotification */
9483                 offset = fConfirmedCOVNotificationRequest (tvb, pinfo, tree, offset);
9484                 break;
9485         case 2: /* confirmedEventNotification */
9486                 offset = fConfirmedEventNotificationRequest (tvb, pinfo, tree, offset);
9487                 break;
9488         case 3: /* confirmedGetAlarmSummary conveys no parameters */
9489                 break;
9490         case 4: /* getEnrollmentSummaryRequest */
9491                 offset = fGetEnrollmentSummaryRequest (tvb, pinfo, tree, offset);
9492                 break;
9493         case 5: /* subscribeCOVRequest */
9494                 offset = fSubscribeCOVRequest(tvb, pinfo, tree, offset);
9495                 break;
9496         case 6: /* atomicReadFile-Request */
9497                 offset = fAtomicReadFileRequest(tvb, pinfo, tree, offset);
9498                 break;
9499         case 7: /* atomicWriteFile-Request */
9500                 offset = fAtomicWriteFileRequest(tvb, pinfo, tree, offset);
9501                 break;
9502         case 8: /* AddListElement-Request */
9503                 offset = fAddListElementRequest(tvb, pinfo, tree, offset);
9504                 break;
9505         case 9: /* removeListElement-Request */
9506                 offset = fRemoveListElementRequest(tvb, pinfo, tree, offset);
9507                 break;
9508         case 10: /* createObjectRequest */
9509                 offset = fCreateObjectRequest(tvb, pinfo, tree, offset);
9510                 break;
9511         case 11: /* deleteObject */
9512                 offset = fDeleteObjectRequest(tvb, pinfo, tree, offset);
9513                 break;
9514         case 12:
9515                 offset = fReadPropertyRequest(tvb, pinfo, tree, offset);
9516                 break;
9517         case 13:
9518                 offset = fReadPropertyConditionalRequest(tvb, pinfo, tree, offset);
9519                 break;
9520         case 14:
9521                 offset = fReadPropertyMultipleRequest(tvb, pinfo, tree, offset);
9522                 break;
9523         case 15:
9524                 offset = fWritePropertyRequest(tvb, pinfo, tree, offset);
9525                 break;
9526         case 16:
9527                 offset = fWritePropertyMultipleRequest(tvb, pinfo, tree, offset);
9528                 break;
9529         case 17:
9530                 offset = fDeviceCommunicationControlRequest(tvb, tree, offset);
9531                 break;
9532         case 18:
9533                 offset = fConfirmedPrivateTransferRequest(tvb, pinfo, tree, offset);
9534                 break;
9535         case 19:
9536                 offset = fConfirmedTextMessageRequest(tvb, pinfo, tree, offset);
9537                 break;
9538         case 20:
9539                 offset = fReinitializeDeviceRequest(tvb, tree, offset);
9540                 break;
9541         case 21:
9542                 offset = fVtOpenRequest(tvb, pinfo, tree, offset);
9543                 break;
9544         case 22:
9545                 offset = fVtCloseRequest (tvb, pinfo, tree, offset);
9546                 break;
9547         case 23:
9548                 offset = fVtDataRequest (tvb, pinfo, tree, offset);
9549                 break;
9550         case 24:
9551                 offset = fAuthenticateRequest (tvb, tree, offset);
9552                 break;
9553         case 25:
9554                 offset = fRequestKeyRequest (tvb, pinfo, tree, offset);
9555                 break;
9556         case 26:
9557                 offset = fReadRangeRequest (tvb, pinfo, tree, offset);
9558                 break;
9559         case 27:
9560                 offset = fLifeSafetyOperationRequest(tvb, pinfo, tree, offset, NULL);
9561                 break;
9562         case 28:
9563                 offset = fSubscribeCOVPropertyRequest(tvb, pinfo, tree, offset);
9564                 break;
9565         case 29:
9566                 offset = fGetEventInformationRequest (tvb, pinfo, tree, offset);
9567                 break;
9568         default:
9569                 return offset;
9570         }
9571         return offset;
9572 }
9573
9574 static guint
9575 fConfirmedServiceAck (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice)
9576 {
9577         if (tvb_reported_length_remaining(tvb,offset) <= 0)
9578                 return offset;
9579
9580         switch (service_choice) {
9581         case 3: /* confirmedEventNotificationAck */
9582                 offset = fGetAlarmSummaryAck (tvb, pinfo, tree, offset);
9583                 break;
9584         case 4: /* getEnrollmentSummaryAck */
9585                 offset = fGetEnrollmentSummaryAck (tvb, pinfo, tree, offset);
9586                 break;
9587         case 6: /* atomicReadFile */
9588                 offset = fAtomicReadFileAck (tvb, pinfo, tree, offset);
9589                 break;
9590         case 7: /* atomicReadFileAck */
9591                 offset = fAtomicWriteFileAck (tvb, tree, offset);
9592                 break;
9593         case 10: /* createObject */
9594                 offset = fCreateObjectAck (tvb, pinfo, tree, offset);
9595                 break;
9596         case 12:
9597                 offset = fReadPropertyAck (tvb, pinfo, tree, offset);
9598                 break;
9599         case 13:
9600                 offset = fReadPropertyConditionalAck (tvb, pinfo, tree, offset);
9601                 break;
9602         case 14:
9603                 offset = fReadPropertyMultipleAck (tvb, pinfo, tree, offset);
9604                 break;
9605         case 18:
9606                 offset = fConfirmedPrivateTransferAck(tvb, pinfo, tree, offset);
9607                 break;
9608         case 21:
9609                 offset = fVtOpenAck (tvb, pinfo, tree, offset);
9610                 break;
9611         case 23:
9612                 offset = fVtDataAck (tvb, tree, offset);
9613                 break;
9614         case 24:
9615                 offset = fAuthenticateAck (tvb, pinfo, tree, offset);
9616                 break;
9617         case 26:
9618                 offset = fReadRangeAck (tvb, pinfo, tree, offset);
9619                 break;
9620         case 29:
9621                 offset = fGetEventInformationACK (tvb, pinfo, tree, offset);
9622                 break;
9623         default:
9624                 return offset;
9625         }
9626         return offset;
9627 }
9628
9629 static guint
9630 fIAmRequest  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9631 {
9632         /* BACnetObjectIdentifier */
9633         offset = fApplicationTypes (tvb, pinfo, tree, offset, "BACnet Object Identifier: ");
9634
9635         /* MaxAPDULengthAccepted */
9636         offset = fApplicationTypes (tvb, pinfo, tree, offset, "Maximum ADPU Length Accepted: ");
9637
9638         /* segmentationSupported */
9639         offset = fApplicationTypesEnumerated (tvb, pinfo, tree, offset,
9640                 "Segmentation Supported: ", BACnetSegmentation);
9641
9642         /* vendor ID */
9643         return fVendorIdentifier (tvb, pinfo, tree, offset);
9644 }
9645
9646 static guint
9647 fIHaveRequest  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9648 {
9649         /* BACnetDeviceIdentifier */
9650         offset = fApplicationTypes (tvb, pinfo, tree, offset, "Device Identifier: ");
9651
9652         /* BACnetObjectIdentifier */
9653         offset = fApplicationTypes (tvb, pinfo, tree, offset, "Object Identifier: ");
9654
9655         /* ObjectName */
9656         return fApplicationTypes (tvb, pinfo, tree, offset, "Object Name: ");
9657
9658 }
9659
9660 static guint
9661 fWhoIsRequest  (tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, guint offset)
9662 {
9663         guint lastoffset = 0;
9664         guint val;
9665         guint8 tag_len;
9666
9667         guint8 tag_no, tag_info;
9668         guint32 lvt;
9669
9670         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
9671                 lastoffset = offset;
9672
9673                 tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9674
9675                 switch (tag_no) {
9676                 case 0:
9677                         /* DeviceInstanceRangeLowLimit Optional */
9678                         fUnsigned32(tvb, offset+tag_len, lvt, &val);
9679                         if (col_get_writable(pinfo->cinfo))
9680                                 col_append_fstr(pinfo->cinfo, COL_INFO, "%d ", val);
9681                         offset = fDevice_Instance (tvb, tree, offset,
9682                                 hf_Device_Instance_Range_Low_Limit);
9683                         break;
9684                 case 1:
9685                         /* DeviceInstanceRangeHighLimit Optional but
9686                                 required if DeviceInstanceRangeLowLimit is there */
9687                         fUnsigned32(tvb, offset+tag_len, lvt, &val);
9688                         if (col_get_writable(pinfo->cinfo))
9689                                 col_append_fstr(pinfo->cinfo, COL_INFO, "%d ", val);
9690                         offset = fDevice_Instance (tvb, tree, offset,
9691                                 hf_Device_Instance_Range_High_Limit);
9692                         break;
9693                 default:
9694                         return offset;
9695                 }
9696                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9697         }
9698         return offset;
9699 }
9700
9701 static guint
9702 fUnconfirmedServiceRequest  (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, gint service_choice)
9703 {
9704         if (tvb_reported_length_remaining(tvb,offset) <= 0)
9705                 return offset;
9706
9707         switch (service_choice) {
9708         case 0: /* I-Am-Request */
9709                 offset = fIAmRequest  (tvb, pinfo, tree, offset);
9710                 break;
9711         case 1: /* i-Have Request */
9712                 offset = fIHaveRequest  (tvb, pinfo, tree, offset);
9713         break;
9714         case 2: /* unconfirmedCOVNotification */
9715                 offset = fUnconfirmedCOVNotificationRequest (tvb, pinfo, tree, offset);
9716                 break;
9717         case 3: /* unconfirmedEventNotification */
9718                 offset = fUnconfirmedEventNotificationRequest (tvb, pinfo, tree, offset);
9719                 break;
9720         case 4: /* unconfirmedPrivateTransfer */
9721                 offset = fUnconfirmedPrivateTransferRequest(tvb, pinfo, tree, offset);
9722                 break;
9723         case 5: /* unconfirmedTextMessage */
9724                 offset = fUnconfirmedTextMessageRequest(tvb, pinfo, tree, offset);
9725                 break;
9726         case 6: /* timeSynchronization */
9727                 offset = fTimeSynchronizationRequest  (tvb, tree, offset);
9728                 break;
9729         case 7: /* who-Has */
9730                 offset = fWhoHas (tvb, pinfo, tree, offset);
9731                 break;
9732         case 8: /* who-Is */
9733                 offset = fWhoIsRequest  (tvb, pinfo, tree, offset);
9734                 break;
9735         case 9: /* utcTimeSynchronization */
9736                 offset = fUTCTimeSynchronizationRequest  (tvb, tree, offset);
9737                 break;
9738         default:
9739                 break;
9740         }
9741         return offset;
9742 }
9743
9744 static guint
9745 fStartConfirmed(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset, guint8 ack,
9746                 gint *svc, proto_item **tt)
9747 {
9748         proto_item *tc;
9749         proto_tree *bacapp_tree_control;
9750         gint tmp;
9751         guint extra = 2;
9752
9753         bacapp_seq = 0;
9754         tmp = (gint) tvb_get_guint8(tvb, offset);
9755         bacapp_flags = tmp & 0x0f;
9756
9757         if (ack == 0) {
9758                 extra = 3;
9759         }
9760         *svc = (gint) tvb_get_guint8(tvb, offset+extra);
9761         if (bacapp_flags & 0x08)
9762                 *svc = (gint) tvb_get_guint8(tvb, offset+extra+2);
9763
9764         proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, ENC_BIG_ENDIAN);
9765         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_pduflags, tvb, offset, 1, ENC_BIG_ENDIAN);
9766         bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp_control);
9767
9768         proto_tree_add_item(bacapp_tree_control, hf_bacapp_SEG, tvb, offset, 1, ENC_BIG_ENDIAN);
9769         proto_tree_add_item(bacapp_tree_control, hf_bacapp_MOR, tvb, offset, 1, ENC_BIG_ENDIAN);
9770         if (ack == 0) { /* The following are for ConfirmedRequest, not Complex ack */
9771             proto_tree_add_item(bacapp_tree_control, hf_bacapp_SA, tvb, offset++, 1, ENC_BIG_ENDIAN);
9772             proto_tree_add_item(bacapp_tree, hf_bacapp_response_segments, tvb,
9773                                                         offset, 1, ENC_BIG_ENDIAN);
9774             proto_tree_add_item(bacapp_tree, hf_bacapp_max_adpu_size, tvb,
9775                                                         offset, 1, ENC_BIG_ENDIAN);
9776         }
9777         offset++;
9778         proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb, offset++, 1, ENC_BIG_ENDIAN);
9779         if (bacapp_flags & 0x08) {
9780                 bacapp_seq = tvb_get_guint8(tvb, offset);
9781                 proto_tree_add_item(bacapp_tree, hf_bacapp_sequence_number, tvb,
9782                     offset++, 1, ENC_BIG_ENDIAN);
9783                 proto_tree_add_item(bacapp_tree, hf_bacapp_window_size, tvb,
9784                     offset++, 1, ENC_BIG_ENDIAN);
9785         }
9786         *tt = proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
9787                                   offset++, 1, ENC_BIG_ENDIAN);
9788         return offset;
9789 }
9790
9791 static guint
9792 fContinueConfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset, gint svc)
9793 {       /* BACnet-Confirmed-Request */
9794         /* ASHRAE 135-2001 20.1.2 */
9795
9796         return fConfirmedServiceRequest (tvb, pinfo, bacapp_tree, offset, svc);
9797 }
9798
9799 static guint
9800 fConfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset)
9801 {       /* BACnet-Confirmed-Request */
9802         /* ASHRAE 135-2001 20.1.2 */
9803         gint svc;
9804         proto_item *tt = 0;
9805
9806         offset = fStartConfirmed(tvb, pinfo, bacapp_tree, offset, 0, &svc, &tt);
9807         return fContinueConfirmedRequestPDU(tvb, pinfo, bacapp_tree, offset, svc);
9808 }
9809
9810 static guint
9811 fUnconfirmedRequestPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset)
9812 {       /* BACnet-Unconfirmed-Request-PDU */
9813         /* ASHRAE 135-2001 20.1.3 */
9814
9815         gint tmp;
9816
9817         proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, ENC_BIG_ENDIAN);
9818
9819         tmp = tvb_get_guint8(tvb, offset);
9820         proto_tree_add_item(bacapp_tree, hf_bacapp_uservice, tvb,
9821             offset++, 1, ENC_BIG_ENDIAN);
9822         /* Service Request follows... Variable Encoding 20.2ff */
9823         return fUnconfirmedServiceRequest  (tvb, pinfo, bacapp_tree, offset, tmp);
9824 }
9825
9826 static guint
9827 fSimpleAckPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset)
9828 {       /* BACnet-Simple-Ack-PDU */
9829         /* ASHRAE 135-2001 20.1.4 */
9830
9831         proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, ENC_BIG_ENDIAN);
9832
9833         proto_tree_add_item(bacapp_tree, hf_bacapp_invoke_id, tvb,
9834                             offset++, 1, ENC_BIG_ENDIAN);
9835         proto_tree_add_item(bacapp_tree, hf_bacapp_service, tvb,
9836                             offset++, 1, ENC_BIG_ENDIAN);
9837
9838         return offset;
9839 }
9840
9841 static guint
9842 fContinueComplexAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset, gint svc)
9843 {       /* BACnet-Complex-Ack-PDU */
9844         /* ASHRAE 135-2001 20.1.5 */
9845
9846         /* Service ACK follows... */
9847         return fConfirmedServiceAck (tvb, pinfo, bacapp_tree, offset, svc);
9848 }
9849
9850 static guint
9851 fComplexAckPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset)
9852 {       /* BACnet-Complex-Ack-PDU */
9853         /* ASHRAE 135-2001 20.1.5 */
9854         gint svc;
9855         proto_item *tt = 0;
9856
9857         offset = fStartConfirmed(tvb, pinfo, bacapp_tree, offset, 1, &svc, &tt);
9858         return fContinueComplexAckPDU(tvb, pinfo, bacapp_tree, offset, svc);
9859 }
9860
9861 static guint
9862 fSegmentAckPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset)
9863 {       /* BACnet-SegmentAck-PDU */
9864         /* ASHRAE 135-2001 20.1.6 */
9865
9866         proto_item *tc;
9867         proto_tree *bacapp_tree_control;
9868
9869         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, ENC_BIG_ENDIAN);
9870         bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
9871
9872         proto_tree_add_item(bacapp_tree_control, hf_bacapp_NAK, tvb, offset, 1, ENC_BIG_ENDIAN);
9873         proto_tree_add_item(bacapp_tree_control, hf_bacapp_SRV, tvb, offset++, 1, ENC_BIG_ENDIAN);
9874         proto_tree_add_item(bacapp_tree_control, hf_bacapp_invoke_id, tvb,
9875                             offset++, 1, ENC_BIG_ENDIAN);
9876         proto_tree_add_item(bacapp_tree_control, hf_bacapp_sequence_number, tvb,
9877                             offset++, 1, ENC_BIG_ENDIAN);
9878         proto_tree_add_item(bacapp_tree_control, hf_bacapp_window_size, tvb,
9879                             offset++, 1, ENC_BIG_ENDIAN);
9880         return offset;
9881 }
9882
9883 static guint
9884 fContextTaggedError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9885 {
9886         guint8 tag_info = 0;
9887         guint8 parsed_tag = 0;
9888         guint32 lvt = 0;
9889         offset += fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt);
9890         offset = fError(tvb, pinfo, tree, offset);
9891         return offset + fTagHeaderTree(tvb, tree, offset, &parsed_tag, &tag_info, &lvt);
9892 }
9893
9894 static guint
9895 fConfirmedPrivateTransferError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9896 {
9897         guint lastoffset = 0;
9898         guint8 tag_no = 0, tag_info = 0;
9899         guint32 lvt = 0;
9900         proto_tree *subtree = tree;
9901         proto_item *tt;
9902
9903         guint vendor_identifier = 0;
9904         guint service_number = 0;
9905         guint8 tag_len = 0;
9906
9907         while (tvb_reported_length_remaining(tvb, offset)) {
9908                 /* exit loop if nothing happens inside */
9909                 lastoffset = offset;
9910                 tag_len = fTagHeader (tvb, offset, &tag_no, &tag_info, &lvt);
9911                 switch (tag_no) {
9912                 case 0: /* errorType */
9913                         offset = fContextTaggedError(tvb, pinfo, subtree, offset);
9914                         break;
9915                 case 1: /* vendorID */
9916                         fUnsigned32(tvb, offset+tag_len, lvt, &vendor_identifier);
9917                         if (col_get_writable(pinfo->cinfo))
9918                                 col_append_fstr(pinfo->cinfo, COL_INFO, "V=%u ",        vendor_identifier);
9919                         offset = fVendorIdentifier (tvb, pinfo, subtree, offset);
9920                         break;
9921                 case 2: /* serviceNumber */
9922                         fUnsigned32(tvb, offset+tag_len, lvt, &service_number);
9923                         if (col_get_writable(pinfo->cinfo))
9924                                 col_append_fstr(pinfo->cinfo, COL_INFO, "SN=%u ",       service_number);
9925                         offset = fUnsignedTag (tvb, subtree, offset, "service Number: ");
9926                         break;
9927                 case 3: /* errorParameters */
9928                         if (tag_is_opening(tag_info)) {
9929                                 tt = proto_tree_add_text(subtree, tvb, offset, 1,
9930                                         "error Parameters");
9931                                 subtree = proto_item_add_subtree(tt, ett_bacapp_value);
9932                                 propertyIdentifier = -1;
9933                                 offset += fTagHeaderTree(tvb, subtree, offset, &tag_no, &tag_info, &lvt);
9934                                 offset = fAbstractSyntaxNType (tvb, pinfo, subtree, offset);
9935                         } else if (tag_is_closing(tag_info)) {
9936                                 offset += fTagHeaderTree (tvb, subtree, offset,
9937                                         &tag_no, &tag_info, &lvt);
9938                                 subtree = tree;
9939                         } else {
9940                                 /* error condition: let caller handle */
9941                                 return offset;
9942                         }
9943                         break;
9944                 default:
9945                         return offset;
9946                 }
9947                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9948         }
9949         return offset;
9950 }
9951
9952 static guint
9953 fCreateObjectError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9954 {
9955         guint lastoffset = 0;
9956
9957         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
9958                 lastoffset = offset;
9959                 switch (fTagNo(tvb, offset)) {
9960                 case 0: /* errorType */
9961                         offset = fContextTaggedError(tvb, pinfo, tree, offset);
9962                         break;
9963                 case 1: /* firstFailedElementNumber */
9964                         offset = fUnsignedTag (tvb,tree,offset,"first failed element number: ");
9965                         break;
9966                 default:
9967                         return offset;
9968                 }
9969                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
9970         }
9971         return offset;
9972 }
9973
9974 static guint
9975 fChangeListError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9976 {
9977         /* Identical to CreateObjectError */
9978         return fCreateObjectError(tvb, pinfo, tree, offset);
9979 }
9980
9981 static guint
9982 fVTCloseError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
9983 {
9984         guint8 tag_no = 0, tag_info = 0;
9985         guint32 lvt = 0;
9986
9987         if (fTagNo(tvb, offset) == 0) {
9988                 /* errorType */
9989                 offset = fContextTaggedError(tvb, pinfo, tree,offset);
9990                 if (fTagNo(tvb, offset) == 1) {
9991                         /* listOfVTSessionIdentifiers [OPTIONAL] */
9992                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
9993                         offset = fVtCloseRequest (tvb, pinfo, tree, offset);
9994                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
9995                 }
9996         }
9997         /* should report bad packet if initial tag wasn't 0 */
9998         return offset;
9999 }
10000
10001 static guint
10002 fWritePropertyMultipleError(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
10003 {
10004         guint lastoffset = 0;
10005         guint8 tag_no = 0, tag_info = 0;
10006         guint32 lvt = 0;
10007
10008         col_set_writable(pinfo->cinfo, FALSE); /* don't set all infos into INFO column */
10009         while (tvb_reported_length_remaining(tvb, offset)) {  /* exit loop if nothing happens inside */
10010                 lastoffset = offset;
10011                 switch (fTagNo(tvb, offset)) {
10012                 case 0: /* errorType */
10013                         offset = fContextTaggedError(tvb, pinfo, tree, offset);
10014                         break;
10015                 case 1: /* firstFailedWriteAttempt */
10016                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
10017                         offset = fBACnetObjectPropertyReference(tvb, pinfo, tree, offset);
10018                         offset += fTagHeaderTree(tvb, tree, offset, &tag_no, &tag_info, &lvt);
10019                         break;
10020                 default:
10021                         return offset;
10022                 }
10023                 if (offset == lastoffset) break;     /* nothing happened, exit loop */
10024         }
10025         return offset;
10026 }
10027
10028 static guint
10029 fError (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset)
10030 {
10031         offset = fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset,
10032                                                    "error Class: ", BACnetErrorClass, 64);
10033         return fApplicationTypesEnumeratedSplit (tvb, pinfo, tree, offset,
10034                                                  "error Code: ", BACnetErrorCode, 256);
10035 }
10036
10037 static guint
10038 fBACnetError (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint offset, guint service)
10039 {
10040         switch (service) {
10041         case 8:  /* no break here !!!! */
10042         case 9:
10043                 offset = fChangeListError (tvb, pinfo, tree, offset);
10044                 break;
10045         case 10:
10046                 offset = fCreateObjectError (tvb, pinfo, tree, offset);
10047                 break;
10048         case 16:
10049                 offset = fWritePropertyMultipleError (tvb, pinfo, tree, offset);
10050                 break;
10051         case 18:
10052                 offset = fConfirmedPrivateTransferError (tvb,pinfo,tree,offset);
10053                 break;
10054         case 22:
10055                 offset = fVTCloseError (tvb, pinfo, tree, offset);
10056                 break;
10057         default:
10058                 return fError (tvb, pinfo, tree, offset);
10059         }
10060         return offset;
10061 }
10062
10063 static guint
10064 fErrorPDU(tvbuff_t *tvb, packet_info *pinfo, proto_tree *bacapp_tree, guint offset)
10065 {       /* BACnet-Error-PDU */
10066         /* ASHRAE 135-2001 20.1.7 */
10067
10068         proto_item *tc;
10069         proto_tree *bacapp_tree_control;
10070         guint8 tmp;
10071
10072         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, ENC_BIG_ENDIAN);
10073         bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
10074
10075         proto_tree_add_item(bacapp_tree_control, hf_bacapp_invoke_id, tvb,
10076                             offset++, 1, ENC_BIG_ENDIAN);
10077         tmp = tvb_get_guint8(tvb, offset);
10078         proto_tree_add_item(bacapp_tree_control, hf_bacapp_service, tvb,
10079                                  offset++, 1, ENC_BIG_ENDIAN);
10080         /* Error Handling follows... */
10081         return fBACnetError (tvb, pinfo, bacapp_tree, offset, tmp);
10082 }
10083
10084 static guint
10085 fRejectPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset)
10086 {       /* BACnet-Reject-PDU */
10087         /* ASHRAE 135-2001 20.1.8 */
10088
10089         proto_item *tc;
10090         proto_tree *bacapp_tree_control;
10091
10092         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset++, 1, ENC_BIG_ENDIAN);
10093         bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
10094
10095         proto_tree_add_item(bacapp_tree_control, hf_bacapp_invoke_id, tvb,
10096                             offset++, 1, ENC_BIG_ENDIAN);
10097         proto_tree_add_item(bacapp_tree_control, hf_BACnetRejectReason, tvb,
10098                             offset++, 1, ENC_BIG_ENDIAN);
10099         return offset;
10100 }
10101
10102 static guint
10103 fAbortPDU(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *bacapp_tree, guint offset)
10104 {       /* BACnet-Abort-PDU */
10105         /* ASHRAE 135-2001 20.1.9 */
10106
10107         proto_item *tc;
10108         proto_tree *bacapp_tree_control;
10109
10110         tc = proto_tree_add_item(bacapp_tree, hf_bacapp_type, tvb, offset, 1, ENC_BIG_ENDIAN);
10111         bacapp_tree_control = proto_item_add_subtree(tc, ett_bacapp);
10112
10113         proto_tree_add_item(bacapp_tree_control, hf_bacapp_SRV, tvb, offset++, 1, ENC_BIG_ENDIAN);
10114         proto_tree_add_item(bacapp_tree_control, hf_bacapp_invoke_id, tvb,
10115                             offset++, 1, ENC_BIG_ENDIAN);
10116         proto_tree_add_item(bacapp_tree_control, hf_BACnetAbortReason, tvb,
10117                             offset++, 1, ENC_BIG_ENDIAN);
10118         return offset;
10119 }
10120
10121 static guint
10122 do_the_dissection(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
10123 {
10124         guint8 flag, bacapp_type;
10125         guint offset = 0;
10126
10127         flag = (gint) tvb_get_guint8(tvb, 0);
10128         bacapp_type = (flag >> 4) & 0x0f;
10129
10130         if (tvb == NULL) {
10131                 return 0;
10132         }
10133
10134         /* ASHRAE 135-2001 20.1.1 */
10135         switch (bacapp_type) {
10136         case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:     /* BACnet-Confirmed-Service-Request */
10137                 offset = fConfirmedRequestPDU(tvb, pinfo, tree, offset);
10138                 break;
10139         case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:   /* BACnet-Unconfirmed-Request-PDU */
10140                 offset = fUnconfirmedRequestPDU(tvb, pinfo, tree, offset);
10141                 break;
10142         case BACAPP_TYPE_SIMPLE_ACK:    /* BACnet-Simple-Ack-PDU */
10143                 offset = fSimpleAckPDU(tvb, pinfo, tree, offset);
10144                 break;
10145         case BACAPP_TYPE_COMPLEX_ACK:   /* BACnet-Complex-Ack-PDU */
10146                 offset = fComplexAckPDU(tvb, pinfo, tree, offset);
10147                 break;
10148         case BACAPP_TYPE_SEGMENT_ACK:   /* BACnet-SegmentAck-PDU */
10149                 offset = fSegmentAckPDU(tvb, pinfo, tree, offset);
10150                 break;
10151         case BACAPP_TYPE_ERROR: /* BACnet-Error-PDU */
10152                 offset = fErrorPDU(tvb, pinfo, tree, offset);
10153                 break;
10154         case BACAPP_TYPE_REJECT:        /* BACnet-Reject-PDU */
10155                 offset = fRejectPDU(tvb, pinfo, tree, offset);
10156                 break;
10157         case BACAPP_TYPE_ABORT: /* BACnet-Abort-PDU */
10158                 offset = fAbortPDU(tvb, pinfo, tree, offset);
10159                 break;
10160         }
10161         return offset;
10162 }
10163
10164 static void
10165 dissect_bacapp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
10166 {
10167         guint8 flag, bacapp_type;
10168         guint save_fragmented = FALSE, data_offset = 0, /*bacapp_apdu_size,*/ fragment = FALSE;
10169         tvbuff_t* new_tvb = NULL;
10170         guint offset = 0;
10171         guint8 bacapp_seqno = 0;
10172         guint8 bacapp_service, bacapp_reason/*, bacapp_prop_win_size*/;
10173         guint8 bacapp_invoke_id = 0;
10174         proto_item *ti;
10175         proto_tree *bacapp_tree = NULL;
10176
10177         gint svc = 0;
10178         proto_item *tt = 0;
10179         gint8 ack = 0;
10180
10181         /* Strings for BACnet Statistics */
10182         const gchar errstr[]="ERROR: ";
10183         const gchar rejstr[]="REJECTED: ";
10184         const gchar abortstr[]="ABORTED: ";
10185         const gchar sackstr[]=" (SimpleAck)";
10186         const gchar cackstr[]=" (ComplexAck)";
10187         const gchar uconfsreqstr[]=" (Unconfirmed Service Request)";
10188         const gchar confsreqstr[]=" (Confirmed Service Request)";
10189
10190         col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-APDU");
10191         col_clear (pinfo->cinfo, COL_INFO);
10192
10193         flag = tvb_get_guint8(tvb, 0);
10194         bacapp_type = (flag >> 4) & 0x0f;
10195
10196         /* show some descriptive text in the INFO column */
10197         col_add_fstr(pinfo->cinfo, COL_INFO, "%-16s",
10198                 val_to_str(bacapp_type, BACnetTypeName, "# unknown APDU #"));
10199
10200         bacinfo.service_type = NULL;
10201         bacinfo.invoke_id = NULL;
10202         bacinfo.instance_ident = NULL;
10203         bacinfo.object_ident = NULL;
10204
10205         switch (bacapp_type)
10206         {
10207                 case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
10208                         /* segmented messages have 2 additional bytes */
10209                         if (flag & BACAPP_SEGMENTED_REQUEST) {
10210                                 fragment = TRUE;
10211                                 ack = 0;
10212                                 /* bacapp_apdu_size = fGetMaxAPDUSize(tvb_get_guint8(tvb, offset + 1)); */ /* has 16 values, reserved are 50 Bytes */
10213                                 bacapp_invoke_id = tvb_get_guint8(tvb, offset + 2);
10214                                 bacapp_seqno = tvb_get_guint8(tvb, offset + 3);
10215                                 /* bacapp_prop_win_size = tvb_get_guint8(tvb, offset + 4); */
10216                                 bacapp_service = tvb_get_guint8(tvb, offset + 5);
10217                                 data_offset = 6;
10218                         } else {
10219                                 bacapp_invoke_id = tvb_get_guint8(tvb, offset + 2);
10220                                 bacapp_service = tvb_get_guint8(tvb, offset + 3);
10221                         }
10222                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ",
10223                                 val_to_str(bacapp_service,
10224                                         BACnetConfirmedServiceChoice,
10225                                         bacapp_unknown_service_str),bacapp_invoke_id);
10226
10227                         updateBacnetInfoValue(BACINFO_INVOKEID,
10228                                               ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id));
10229
10230                         updateBacnetInfoValue(BACINFO_SERVICE,
10231                             ep_strconcat(val_to_str(bacapp_service,
10232                                                     BACnetConfirmedServiceChoice,
10233                                                     bacapp_unknown_service_str),
10234                                          confsreqstr, NULL));
10235                         break;
10236                 case BACAPP_TYPE_UNCONFIRMED_SERVICE_REQUEST:
10237                         bacapp_service = tvb_get_guint8(tvb, offset + 1);
10238                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
10239                                 val_to_str(bacapp_service,
10240                                         BACnetUnconfirmedServiceChoice,
10241                                         bacapp_unknown_service_str));
10242
10243                         updateBacnetInfoValue(BACINFO_SERVICE,
10244                             ep_strconcat(val_to_str(bacapp_service,
10245                                                     BACnetUnconfirmedServiceChoice,
10246                                                     bacapp_unknown_service_str),
10247                                          uconfsreqstr, NULL));
10248                         break;
10249                 case BACAPP_TYPE_SIMPLE_ACK:
10250                         bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
10251                         bacapp_service = tvb_get_guint8(tvb, offset + 2);
10252                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */
10253                                 val_to_str(bacapp_service,
10254                                         BACnetConfirmedServiceChoice,
10255                                         bacapp_unknown_service_str), bacapp_invoke_id);
10256
10257                         updateBacnetInfoValue(BACINFO_INVOKEID,
10258                                               ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id));
10259
10260                         updateBacnetInfoValue(BACINFO_SERVICE,
10261                             ep_strconcat(val_to_str(bacapp_service,
10262                                                     BACnetConfirmedServiceChoice,
10263                                                     bacapp_unknown_service_str),
10264                                          sackstr, NULL));
10265                         break;
10266                 case BACAPP_TYPE_COMPLEX_ACK:
10267                         /* segmented messages have 2 additional bytes */
10268                         if (flag & BACAPP_SEGMENTED_REQUEST) {
10269                                 fragment = TRUE;
10270                                 ack = 1;
10271                                 /* bacapp_apdu_size = fGetMaxAPDUSize(0); */ /* has minimum of 50 Bytes */
10272                                 bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
10273                                 bacapp_seqno = tvb_get_guint8(tvb, offset + 2);
10274                                 /* bacapp_prop_win_size = tvb_get_guint8(tvb, offset + 3); */
10275                                 bacapp_service = tvb_get_guint8(tvb, offset + 4);
10276                                 data_offset = 5;
10277                         } else {
10278                                 bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
10279                                 bacapp_service = tvb_get_guint8(tvb, offset + 2);
10280                         }
10281                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */
10282                                 val_to_str(bacapp_service,
10283                                         BACnetConfirmedServiceChoice,
10284                                         bacapp_unknown_service_str), bacapp_invoke_id);
10285
10286                         updateBacnetInfoValue(BACINFO_INVOKEID,
10287                                               ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id));
10288
10289                         updateBacnetInfoValue(BACINFO_SERVICE,
10290                             ep_strconcat(val_to_str(bacapp_service,
10291                                                     BACnetConfirmedServiceChoice,
10292                                                     bacapp_unknown_service_str),
10293                                          cackstr, NULL));
10294                         break;
10295                 case BACAPP_TYPE_SEGMENT_ACK:
10296                         /* nothing more to add */
10297                         break;
10298                 case BACAPP_TYPE_ERROR:
10299                         bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
10300                         bacapp_service = tvb_get_guint8(tvb, offset + 2);
10301                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */
10302                                 val_to_str(bacapp_service,
10303                                         BACnetConfirmedServiceChoice,
10304                                         bacapp_unknown_service_str), bacapp_invoke_id);
10305
10306                         updateBacnetInfoValue(BACINFO_INVOKEID,
10307                                               ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id));
10308
10309                         updateBacnetInfoValue(BACINFO_SERVICE,
10310                             ep_strconcat(errstr,
10311                                          val_to_str(bacapp_service,
10312                                                     BACnetConfirmedServiceChoice,
10313                                                     bacapp_unknown_service_str),
10314                                          NULL));
10315                         break;
10316                 case BACAPP_TYPE_REJECT:
10317                         bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
10318                         bacapp_reason = tvb_get_guint8(tvb, offset + 2);
10319                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */
10320                                 val_to_split_str(bacapp_reason,
10321                                         64,
10322                                         BACnetRejectReason,
10323                                         ASHRAE_Reserved_Fmt,
10324                                         Vendor_Proprietary_Fmt), bacapp_invoke_id);
10325
10326                         updateBacnetInfoValue(BACINFO_INVOKEID,
10327                                               ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id));
10328
10329                         updateBacnetInfoValue(BACINFO_SERVICE,
10330                                 ep_strconcat(rejstr,
10331                                              val_to_split_str(bacapp_reason, 64,
10332                                              BACnetRejectReason,
10333                                              ASHRAE_Reserved_Fmt,
10334                                              Vendor_Proprietary_Fmt),
10335                                              NULL));
10336                         break;
10337                 case BACAPP_TYPE_ABORT:
10338                         bacapp_invoke_id = tvb_get_guint8(tvb, offset + 1);
10339                         bacapp_reason = tvb_get_guint8(tvb, offset + 2);
10340                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s[%3u] ", /* "original-invokeID" replaced */
10341                                 val_to_split_str(bacapp_reason,
10342                                         64,
10343                                         BACnetAbortReason,
10344                                         ASHRAE_Reserved_Fmt,
10345                                         Vendor_Proprietary_Fmt), bacapp_invoke_id);
10346
10347                         updateBacnetInfoValue(BACINFO_INVOKEID,
10348                                               ep_strdup_printf("Invoke ID: %d", bacapp_invoke_id));
10349
10350                         updateBacnetInfoValue(BACINFO_SERVICE,
10351                                 ep_strconcat(abortstr,
10352                                              val_to_split_str(bacapp_reason,
10353                                                               64,
10354                                                               BACnetAbortReason,
10355                                                               ASHRAE_Reserved_Fmt,
10356                                                               Vendor_Proprietary_Fmt),
10357                                              NULL));
10358                         break;
10359                 /* UNKNOWN */
10360                 default:
10361                         /* nothing more to add */
10362                         break;
10363         }
10364
10365         save_fragmented = pinfo->fragmented;
10366
10367         ti = proto_tree_add_item(tree, proto_bacapp, tvb, offset, -1, ENC_NA);
10368         bacapp_tree = proto_item_add_subtree(ti, ett_bacapp);
10369
10370         if (!fragment)
10371                 offset = do_the_dissection(tvb,pinfo,bacapp_tree);
10372         else
10373                 fStartConfirmed(tvb, pinfo, bacapp_tree, offset, ack, &svc, &tt);
10374                         /* not resetting the offset so the remaining can be done */
10375
10376         if (fragment) { /* fragmented */
10377                 fragment_data *frag_msg = NULL;
10378
10379                 new_tvb = NULL;
10380                 pinfo->fragmented = TRUE;
10381
10382                 frag_msg = fragment_add_seq_check(tvb, data_offset, pinfo,
10383                         bacapp_invoke_id, /* ID for fragments belonging together */
10384                         msg_fragment_table, /* list of message fragments */
10385                         msg_reassembled_table, /* list of reassembled messages */
10386                         bacapp_seqno, /* fragment sequence number */
10387                         tvb_reported_length_remaining(tvb, data_offset), /* fragment length - to the end */
10388                         flag & BACAPP_MORE_SEGMENTS); /* Last fragment reached? */
10389                 new_tvb = process_reassembled_data(tvb, data_offset, pinfo,
10390                                 "Reassembled BACapp", frag_msg, &msg_frag_items,
10391                                 NULL, tree);
10392
10393                 if (new_tvb) { /* Reassembled */
10394                         col_append_str(pinfo->cinfo, COL_INFO,
10395                                 " (Message Reassembled)");
10396                 } else { /* Not last packet of reassembled Short Message */
10397                         col_append_fstr(pinfo->cinfo, COL_INFO,
10398                         " (Message fragment %u)", bacapp_seqno);
10399                 }
10400                 if (new_tvb) { /* take it all */
10401                         switch (bacapp_type)
10402                         {
10403                                 case BACAPP_TYPE_CONFIRMED_SERVICE_REQUEST:
10404                                         fContinueConfirmedRequestPDU(new_tvb, pinfo, bacapp_tree, 0, svc);
10405                                 break;
10406                                 case BACAPP_TYPE_COMPLEX_ACK:
10407                                         fContinueComplexAckPDU(new_tvb, pinfo, bacapp_tree, 0, svc);
10408                                 break;
10409                                 default:
10410                                         /* do nothing */
10411                                 break;
10412                         }
10413                         /* } */
10414                 }
10415         }
10416
10417         pinfo->fragmented = save_fragmented;
10418
10419         /* tapping */
10420         tap_queue_packet(bacapp_tap,pinfo,&bacinfo);
10421 }
10422
10423 static void
10424 bacapp_init_routine(void)
10425 {
10426         fragment_table_init(&msg_fragment_table);
10427         reassembled_table_init(&msg_reassembled_table);
10428 }
10429
10430 static guint32
10431 fConvertXXXtoUTF8 (gchar *in, gsize *inbytesleft, gchar *out, gsize *outbytesleft, const gchar *fromcoding)
10432 {
10433         guint32 i;
10434         GIConv icd;
10435
10436         if ((icd = g_iconv_open ("UTF-8", fromcoding)) != (GIConv) -1) {
10437                 i = (guint32) g_iconv (icd, &in, inbytesleft, &out, outbytesleft);
10438                 /* g_iconv incremented 'out'; now ensure it's NULL terminated */
10439                 out[0] = '\0';
10440
10441                 g_iconv_close (icd);
10442                 return i;
10443         }
10444
10445         uni_to_string(in,*inbytesleft,out);
10446         out[*inbytesleft] = '\0';
10447         *outbytesleft -= *inbytesleft;
10448         *inbytesleft = 0;
10449
10450         return 0;
10451 }
10452
10453 static void
10454 uni_to_string(char * data, gsize str_length, char *dest_buf)
10455 {
10456         gint i;
10457         guint16 c_char;
10458         gsize length_remaining = 0;
10459
10460         length_remaining = str_length;
10461         dest_buf[0] = '\0';
10462         if(str_length == 0) {
10463                 return;
10464         }
10465         for ( i = 0; i < (gint) str_length; i++ ) {
10466                 c_char = data[i];
10467                 if (c_char<0x20 || c_char>0x7e) {
10468                         if (c_char != 0x00) {
10469                                 c_char = '.';
10470                                 dest_buf[i] = c_char & 0xff;
10471                         } else {
10472                                 i--;
10473                                 str_length--;
10474                         }
10475                 } else {
10476                         dest_buf[i] = c_char & 0xff;
10477                 }
10478                 length_remaining--;
10479
10480                 if(length_remaining==0) {
10481                         dest_buf[i+1] = '\0';
10482                         return;
10483                 }
10484         }
10485         if (i < 0) {
10486                 i = 0;
10487         }
10488         dest_buf[i] = '\0';
10489         return;
10490 }
10491
10492 void
10493 proto_register_bacapp(void)
10494 {
10495         static hf_register_info hf[] = {
10496                 { &hf_bacapp_type,
10497                         { "APDU Type",           "bacapp.type",
10498                         FT_UINT8, BASE_DEC, VALS(BACnetTypeName), 0xf0, NULL, HFILL }
10499                 },
10500                 { &hf_bacapp_pduflags,
10501                         { "PDU Flags",                  "bacapp.pduflags",
10502                         FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL }
10503                 },
10504                 { &hf_bacapp_SEG,
10505                         { "Segmented Request",           "bacapp.segmented_request",
10506                         FT_BOOLEAN, 8, TFS(&segments_follow), 0x08, NULL, HFILL }
10507                 },
10508                 { &hf_bacapp_MOR,
10509                         { "More Segments",           "bacapp.more_segments",
10510                         FT_BOOLEAN, 8, TFS(&more_follow), 0x04, "More Segments Follow", HFILL }
10511                 },
10512                 { &hf_bacapp_SA,
10513                         { "SA",           "bacapp.SA",
10514                         FT_BOOLEAN, 8, TFS(&segmented_accept), 0x02, "Segmented Response accepted", HFILL }
10515                 },
10516                 { &hf_bacapp_max_adpu_size,
10517                         { "Size of Maximum ADPU accepted",           "bacapp.max_adpu_size",
10518                         FT_UINT8, BASE_DEC, VALS(BACnetMaxAPDULengthAccepted), 0x0f, NULL, HFILL }
10519                 },
10520                 { &hf_bacapp_response_segments,
10521                         { "Max Response Segments accepted",           "bacapp.response_segments",
10522                         FT_UINT8, BASE_DEC, VALS(BACnetMaxSegmentsAccepted), 0x70, NULL, HFILL }
10523                 },
10524                 { &hf_bacapp_objectType,
10525                         { "Object Type",           "bacapp.objectType",
10526                         FT_UINT32, BASE_DEC, VALS(BACnetObjectType), 0xffc00000, NULL, HFILL }
10527                 },
10528                 { &hf_bacapp_instanceNumber,
10529                         { "Instance Number",           "bacapp.instance_number",
10530                         FT_UINT32, BASE_DEC, NULL, 0x003fffff, NULL, HFILL }
10531                 },
10532                 { &hf_BACnetPropertyIdentifier,
10533                         { "Property Identifier", "bacapp.property_identifier",
10534                         FT_UINT32, BASE_DEC, VALS(BACnetPropertyIdentifier), 0, NULL, HFILL }
10535                 },
10536                 { &hf_BACnetVendorIdentifier,
10537                         { "Vendor Identifier", "bacapp.vendor_identifier",
10538                         FT_UINT16, BASE_DEC, VALS(BACnetVendorIdentifiers), 0, NULL, HFILL }
10539                 },
10540                 { &hf_BACnetRestartReason,
10541                         { "Restart Reason", "bacapp.restart_reason",
10542                         FT_UINT8, BASE_DEC, VALS(BACnetRestartReason), 0, NULL, HFILL }
10543                 },
10544                 { &hf_bacapp_invoke_id,
10545                         { "Invoke ID",           "bacapp.invoke_id",
10546                         FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
10547                 },
10548                 { &hf_bacapp_sequence_number,
10549                         { "Sequence Number",           "bacapp.sequence_number",
10550                         FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
10551                 },
10552                 { &hf_bacapp_window_size,
10553                         { "Proposed Window Size",           "bacapp.window_size",
10554                         FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }
10555                 },
10556                 { &hf_bacapp_service,
10557                         { "Service Choice",           "bacapp.confirmed_service",
10558                         FT_UINT8, BASE_DEC, VALS(BACnetConfirmedServiceChoice), 0x00, NULL, HFILL }
10559                 },
10560                 { &hf_bacapp_uservice,
10561                         { "Unconfirmed Service Choice",           "bacapp.unconfirmed_service",
10562                         FT_UINT8, BASE_DEC, VALS(BACnetUnconfirmedServiceChoice), 0x00, NULL, HFILL }
10563                 },
10564                 { &hf_bacapp_NAK,
10565                         { "NAK",           "bacapp.NAK",
10566                         FT_BOOLEAN, 8, NULL, 0x02, "negative ACK", HFILL }
10567                 },
10568                 { &hf_bacapp_SRV,
10569                         { "SRV",           "bacapp.SRV",
10570                         FT_BOOLEAN, 8, NULL, 0x01, "Server", HFILL }
10571                 },
10572                 { &hf_Device_Instance_Range_Low_Limit,
10573                         { "Device Instance Range Low Limit", "bacapp.who_is.low_limit",
10574                         FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }
10575                 },
10576                 { &hf_Device_Instance_Range_High_Limit,
10577                         { "Device Instance Range High Limit", "bacapp.who_is.high_limit",
10578                         FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }
10579                 },
10580                 { &hf_BACnetRejectReason,
10581                         { "Reject Reason",           "bacapp.reject_reason",
10582                         FT_UINT8, BASE_DEC, VALS(BACnetRejectReason), 0x00, NULL, HFILL }
10583                 },
10584                 { &hf_BACnetAbortReason,
10585                         { "Abort Reason",           "bacapp.abort_reason",
10586                         FT_UINT8, BASE_DEC, VALS(BACnetAbortReason), 0x00, NULL, HFILL }
10587                 },
10588                 { &hf_BACnetApplicationTagNumber,
10589                         { "Application Tag Number",
10590                         "bacapp.application_tag_number",
10591                         FT_UINT8, BASE_DEC, VALS(BACnetApplicationTagNumber), 0xF0,
10592                         NULL, HFILL }
10593                 },
10594                 { &hf_BACnetContextTagNumber,
10595                         { "Context Tag Number",
10596                         "bacapp.context_tag_number",
10597                         FT_UINT8, BASE_DEC, NULL, 0xF0,
10598                         NULL, HFILL }
10599                 },
10600                 { &hf_BACnetExtendedTagNumber,
10601                         { "Extended Tag Number",
10602                         "bacapp.extended_tag_number",
10603                         FT_UINT8, BASE_DEC, NULL, 0,
10604                         NULL, HFILL }
10605                 },
10606                 { &hf_BACnetNamedTag,
10607                         { "Named Tag",
10608                         "bacapp.named_tag",
10609                         FT_UINT8, BASE_DEC, VALS(BACnetTagNames), 0x07,
10610                         NULL, HFILL }
10611                 },
10612                 { &hf_BACnetCharacterSet,
10613                         { "String Character Set",
10614                         "bacapp.string_character_set",
10615                         FT_UINT8, BASE_DEC, VALS(BACnetCharacterSet),0,
10616                         NULL, HFILL }
10617                 },
10618                 { &hf_BACnetTagClass,
10619                         { "Tag Class",           "bacapp.tag_class",
10620                         FT_BOOLEAN, 8, TFS(&BACnetTagClass), 0x08, NULL, HFILL }
10621                 },
10622                 { &hf_bacapp_tag_lvt,
10623                         { "Length Value Type",
10624                         "bacapp.LVT",
10625                         FT_UINT8, BASE_DEC, NULL, 0,
10626                         NULL, HFILL }
10627                 },
10628                 { &hf_bacapp_tag_ProcessId,
10629                         { "ProcessIdentifier",           "bacapp.processId",
10630                         FT_UINT32, BASE_DEC, NULL, 0, "Process Identifier", HFILL }
10631                 },
10632                 { &hf_bacapp_tag_IPV4,
10633                         { "IPV4",           "bacapp.IPV4",
10634                         FT_IPv4, BASE_NONE, NULL, 0, "IP-Address", HFILL }
10635                 },
10636                 { &hf_bacapp_tag_IPV6,
10637                 { "IPV6",           "bacapp.IPV6",
10638                         FT_IPv6, BASE_NONE, NULL, 0, "IP-Address", HFILL }
10639                 },
10640                 { &hf_bacapp_tag_PORT,
10641                         { "Port",           "bacapp.Port",
10642                         FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }
10643                 },
10644                 {&hf_msg_fragments,
10645                         {"Message fragments", "bacapp.fragments",
10646                         FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } },
10647                 {&hf_msg_fragment,
10648                         {"Message fragment", "bacapp.fragment",
10649                         FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
10650                 {&hf_msg_fragment_overlap,
10651                         {"Message fragment overlap", "bacapp.fragment.overlap",
10652                         FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
10653                 {&hf_msg_fragment_overlap_conflicts,
10654                         {"Message fragment overlapping with conflicting data",
10655                         "bacapp.fragment.overlap.conflicts",
10656                         FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
10657                 {&hf_msg_fragment_multiple_tails,
10658                         {"Message has multiple tail fragments",
10659                         "bacapp.fragment.multiple_tails",
10660                         FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
10661                 {&hf_msg_fragment_too_long_fragment,
10662                         {"Message fragment too long", "bacapp.fragment.too_long_fragment",
10663                         FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL } },
10664                 {&hf_msg_fragment_error,
10665                         {"Message defragmentation error", "bacapp.fragment.error",
10666                         FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
10667                 {&hf_msg_fragment_count,
10668                         {"Message fragment count", "bacapp.fragment.count",
10669                         FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } },
10670                 {&hf_msg_reassembled_in,
10671                         {"Reassembled in", "bacapp.reassembled.in",
10672                         FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL } },
10673                 {&hf_msg_reassembled_length,
10674                         {"Reassembled BACapp length", "bacapp.reassembled.length",
10675                         FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL } }
10676         };
10677         static gint *ett[] = {
10678                 &ett_bacapp,
10679                 &ett_bacapp_control,
10680                 &ett_bacapp_tag,
10681                 &ett_bacapp_list,
10682                 &ett_bacapp_value,
10683                 &ett_msg_fragment,
10684                 &ett_msg_fragments
10685
10686         };
10687
10688         proto_bacapp = proto_register_protocol("Building Automation and Control Network APDU",
10689                                                "BACapp", "bacapp");
10690
10691         proto_register_field_array(proto_bacapp, hf, array_length(hf));
10692         proto_register_subtree_array(ett, array_length(ett));
10693         register_dissector("bacapp", dissect_bacapp, proto_bacapp);
10694         register_init_routine (&bacapp_init_routine);
10695
10696         bacapp_dissector_table = register_dissector_table("bacapp.vendor_identifier",
10697                                                           "BACapp Vendor Identifier",
10698                                                           FT_UINT8, BASE_HEX);
10699
10700         /* Register BACnet Statistic trees */
10701         register_bacapp_stat_trees();
10702         bacapp_tap = register_tap("bacapp"); /* BACnet statistics tap */
10703 }
10704
10705 void
10706 proto_reg_handoff_bacapp(void)
10707 {
10708         data_handle = find_dissector("data");
10709 }