From Thomas Anders fix some memory leaks
[obnox/wireshark/wip.git] / packet-bacnet.c
1 /* packet-bacnet.c
2  * Routines for BACnet (NPDU) dissection
3  * Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
4  *
5  * $Id: packet-bacnet.c,v 1.18 2004/05/12 19:55:14 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from README.developer,v 1.23
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <glib.h>
37
38 #include <epan/packet.h>
39
40 #include "llcsaps.h"
41
42 static dissector_handle_t bacapp_handle;
43 static dissector_handle_t data_handle;
44
45 static const char*
46 bacnet_mesgtyp_name (guint8 bacnet_mesgtyp){
47   static const char *type_names[] = {
48         "Who-Is-Router-To-Network",
49         "I-Am-Router-To-Network",
50         "I-Could-Be-Router-To-Network",
51         "Reject-Message-To-Network",
52         "Router-Busy-To-Network",
53         "Router-Available-To-Network",
54         "Initialize-Routing-Table",
55         "Initialize-Routing-Table-Ack",
56         "Establish-Connection-To-Network",
57         "Disconnect-Connection-To-Network"
58         };
59   if(bacnet_mesgtyp < 0x0a) {
60         return type_names[bacnet_mesgtyp];
61   } else {
62         return (bacnet_mesgtyp < 0x80)? "Reserved for Use by ASHRAE" : "Vendor Proprietary Message";
63   }
64 }
65
66 static const char*
67 bacnet_rejectreason_name (guint8 bacnet_rejectreason) {
68   static const char *type_names[] = {
69         "Other error.",
70         "The router is not directly connected to DNET and cannot find a router to DNET on any directly connected network using Who-Is-Router-To-Network messages.",
71         "The router is busy and unable to accept messages for the specified DNET at the present time.",
72         "It is an unknown network layer message type.",
73         "The message is too long to be routed to this DNET.",
74         "The router is no longer directly connected to DNET but can reconnect if requested.",
75         "The router is no longer directly connected to DNET and cannot reconnect even if requested."
76         };
77    return (bacnet_rejectreason > 6)? "Invalid Rejection Reason.":  type_names[bacnet_rejectreason];
78 }
79
80 /* Network Layer Control Information */
81 #define BAC_CONTROL_NET          0x80
82 #define BAC_CONTROL_RES1         0x40
83 #define BAC_CONTROL_DEST         0x20
84 #define BAC_CONTROL_RES2         0x10
85 #define BAC_CONTROL_SRC          0x08
86 #define BAC_CONTROL_EXPECT       0x04
87 #define BAC_CONTROL_PRIO_HIGH    0x02
88 #define BAC_CONTROL_PRIO_LOW     0x01
89
90 /* Network Layer Message Types */
91 #define BAC_NET_WHO_R           0x00
92 #define BAC_NET_IAM_R           0x01
93 #define BAC_NET_ICB_R           0x02
94 #define BAC_NET_REJ             0x03
95 #define BAC_NET_R_BUSY          0x04
96 #define BAC_NET_R_AVA           0x05
97 #define BAC_NET_INIT_RTAB       0x06
98 #define BAC_NET_INIT_RTAB_ACK   0x07
99 #define BAC_NET_EST_CON         0x08
100 #define BAC_NET_DISC_CON        0x09
101
102 static const true_false_string control_net_set_high = {
103         "network layer message, message type field present.",
104         "BACnet APDU, message type field absent."
105 };
106
107 static const true_false_string control_res_high = {
108         "Shall be zero, but is one.",
109         "Shall be zero and is zero."
110 };
111 static const true_false_string control_dest_high = {
112         "DNET, DLEN and Hop Count present. If DLEN=0: broadcast, dest. address field absent.",
113         "DNET, DLEN, DADR and Hop Count absent."
114 };
115
116 static const true_false_string control_src_high = {
117         "SNET, SLEN and SADR present, SLEN=0 invalid, SLEN specifies length of SADR",
118         "SNET, SLEN and SADR absent"
119 };
120
121 static const true_false_string control_expect_high = {
122         "BACnet-Confirmed-Request-PDU, a segment of BACnet-ComplexACK-PDU or Network Message expecting a reply present.",
123         "Other than a BACnet-Confirmed-Request-PDU, segment of BACnet-ComplexACK-PDU or network layer message expecting a reply present."
124 };
125
126 static const true_false_string control_prio_high_high = {
127         "Life Safety or Critical Equipment message.",
128         "Not a Life Safety or Critical Equipment message."
129 };
130
131 static const true_false_string control_prio_low_high = {
132         "Urgent message",
133         "Normal message"
134 };
135
136
137 static int proto_bacnet = -1;
138 static int hf_bacnet_version = -1;
139 static int hf_bacnet_control = -1;
140 static int hf_bacnet_control_net = -1;
141 static int hf_bacnet_control_res1 = -1;
142 static int hf_bacnet_control_dest = -1;
143 static int hf_bacnet_control_res2 = -1;
144 static int hf_bacnet_control_src = -1;
145 static int hf_bacnet_control_expect = -1;
146 static int hf_bacnet_control_prio_high = -1;
147 static int hf_bacnet_control_prio_low = -1;
148 static int hf_bacnet_dnet = -1;
149 static int hf_bacnet_dlen = -1;
150 static int hf_bacnet_dadr_eth = -1;
151 static int hf_bacnet_dadr_tmp = -1;
152 static int hf_bacnet_snet = -1;
153 static int hf_bacnet_slen = -1;
154 static int hf_bacnet_sadr_eth = -1;
155 static int hf_bacnet_sadr_tmp = -1;
156 static int hf_bacnet_hopc = -1;
157 static int hf_bacnet_mesgtyp = -1;
158 static int hf_bacnet_vendor = -1;
159 static int hf_bacnet_perf = -1;
160 static int hf_bacnet_rejectreason = -1;
161 static int hf_bacnet_rportnum = -1;
162 static int hf_bacnet_portid = -1;
163 static int hf_bacnet_pinfolen = -1;
164 static int hf_bacnet_pinfo = -1;
165
166 static gint ett_bacnet = -1;
167 static gint ett_bacnet_control = -1;
168
169 static void
170 dissect_bacnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
171 {
172         proto_item *ti;
173         proto_item *ct;
174         proto_tree *bacnet_tree;
175         proto_tree *control_tree;
176
177         gint offset;
178         guint8 bacnet_version;
179         guint8 bacnet_control;
180         guint8 bacnet_dlen;
181         guint8 bacnet_slen;
182         guint8 bacnet_mesgtyp;
183         guint8 bacnet_rejectreason;
184         guint8 bacnet_rportnum;
185         guint8 bacnet_pinfolen;
186         guint8 i;
187         guint8 j;
188         tvbuff_t *next_tvb;
189
190         if (check_col(pinfo->cinfo, COL_PROTOCOL))
191                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-NPDU");
192
193         if (check_col(pinfo->cinfo, COL_INFO))
194                 col_set_str(pinfo->cinfo, COL_INFO, "Building Automation and Control Network NPDU");
195
196         offset = 0;
197         bacnet_version = tvb_get_guint8(tvb, offset);
198         bacnet_control = tvb_get_guint8(tvb, offset+1);
199         bacnet_dlen = 0;
200         bacnet_slen = 0;
201         bacnet_mesgtyp = 0;
202         bacnet_rejectreason = 0;
203         bacnet_rportnum = 0;
204         bacnet_pinfolen =0;
205         i = 0;
206         j = 0;
207
208 /* I don't know the length of the NPDU by now. Setting the length after dissection */
209         ti = proto_tree_add_item(tree, proto_bacnet, tvb, 0, -1, FALSE);
210
211         bacnet_tree = proto_item_add_subtree(ti, ett_bacnet);
212
213         proto_tree_add_uint_format(bacnet_tree, hf_bacnet_version, tvb,
214                 offset, 1,
215                        bacnet_version,"Version: 0x%02x (%s)",bacnet_version,
216                        (bacnet_version == 0x01)?"ASHRAE 135-1995":"unknown");
217         offset ++;
218         ct = proto_tree_add_uint(bacnet_tree, hf_bacnet_control,
219                 tvb, offset, 1, bacnet_control);
220         control_tree = proto_item_add_subtree(ct, ett_bacnet_control);
221         proto_tree_add_boolean(control_tree, hf_bacnet_control_net,
222                 tvb, offset, 1, bacnet_control);
223         proto_tree_add_boolean(control_tree, hf_bacnet_control_res1, tvb,
224                 offset, 1, bacnet_control);
225         proto_tree_add_boolean(control_tree, hf_bacnet_control_dest, tvb,
226                 offset, 1, bacnet_control);
227         proto_tree_add_boolean(control_tree, hf_bacnet_control_res2, tvb,
228                 offset, 1, bacnet_control);
229         proto_tree_add_boolean(control_tree, hf_bacnet_control_src, tvb,
230                 offset, 1, bacnet_control);
231         proto_tree_add_boolean(control_tree, hf_bacnet_control_expect, tvb,
232                 offset, 1, bacnet_control);
233         proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_high,
234                 tvb, offset, 1, bacnet_control);
235         proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_low,
236                 tvb, offset, 1, bacnet_control);
237         offset ++;
238         if (bacnet_control & BAC_CONTROL_DEST) { /* DNET, DLEN, DADR */
239                 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
240                         tvb, offset, 2, FALSE);
241                 offset += 2;
242                 bacnet_dlen = tvb_get_guint8(tvb, offset);
243                 /* DLEN = 0 is broadcast on dest.network */
244                 if( bacnet_dlen == 0) {
245                         /* append to hf_bacnet_dlen: broadcast */
246                         proto_tree_add_uint_format(bacnet_tree,
247                             hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen,
248                             "Destination MAC Layer Address Length: %d indicates Broadcast on Destination Network",
249                             bacnet_dlen);
250                         offset ++;
251                         /* going to SNET */
252                 } else if (bacnet_dlen==6) {
253                         proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
254                                 tvb, offset, 1, bacnet_dlen);
255                         offset ++;
256                         /* Ethernet MAC */
257                         proto_tree_add_item(bacnet_tree,
258                                 hf_bacnet_dadr_eth, tvb, offset,
259                                 bacnet_dlen, FALSE);
260                         offset += bacnet_dlen;
261                 } else if (bacnet_dlen<7) {
262                         proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
263                                 tvb, offset, 1, bacnet_dlen);
264                         offset ++;
265                         /* Other MAC formats should be included here */
266                         proto_tree_add_item(bacnet_tree,
267                                 hf_bacnet_dadr_tmp, tvb, offset,
268                                 bacnet_dlen, FALSE);
269                         offset += bacnet_dlen;
270                 } else {
271                         proto_tree_add_uint_format(bacnet_tree,
272                             hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen,
273                             "Destination MAC Layer Address Length: %d invalid!",
274                             bacnet_dlen);
275                 }
276         }
277         if (bacnet_control & BAC_CONTROL_SRC) { /* SNET, SLEN, SADR */
278                 /* SNET */
279                 proto_tree_add_uint(bacnet_tree, hf_bacnet_snet,
280                         tvb, offset, 2, tvb_get_ntohs(tvb, offset));
281                 offset += 2;
282                 bacnet_slen = tvb_get_guint8(tvb, offset);
283                 if( bacnet_slen == 0) { /* SLEN = 0 invalid */
284                         proto_tree_add_uint_format(bacnet_tree,
285                             hf_bacnet_slen, tvb, offset, 1, bacnet_slen,
286                             "Source MAC Layer Address Length: %d invalid!",
287                             bacnet_slen);
288                         offset ++;
289                 } else if (bacnet_slen==6) {
290                         /* SLEN */
291                          proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
292                                 tvb, offset, 1, bacnet_slen);
293                         offset ++;
294                         /* Ethernet MAC */
295                         proto_tree_add_item(bacnet_tree,
296                                 hf_bacnet_sadr_eth, tvb, offset,
297                                 bacnet_slen, FALSE);
298                         offset += bacnet_slen;
299                 } else if (bacnet_slen<6) { /* LON,ARCNET,MS/TP MAC */
300                         /* SLEN */
301                          proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
302                                 tvb, offset, 1, bacnet_slen);
303                         offset ++;
304                         /* Other MAC formats should be included here */
305                         proto_tree_add_item(bacnet_tree,
306                                 hf_bacnet_sadr_tmp, tvb, offset,
307                                 bacnet_slen, FALSE);
308                         offset += bacnet_slen;
309                 } else {
310                         proto_tree_add_uint_format(bacnet_tree,
311                         hf_bacnet_slen, tvb, offset, 1, bacnet_slen,
312                             "Source MAC Layer Address Length: %d invalid!",
313                             bacnet_slen);
314                         offset ++;
315                 }
316         }
317         if (bacnet_control & BAC_CONTROL_DEST) { /* Hopcount */
318                 proto_tree_add_item(bacnet_tree, hf_bacnet_hopc,
319                         tvb, offset, 1, FALSE);
320                 offset ++;
321         }
322         /* Network Layer Message Type */
323         if (bacnet_control & BAC_CONTROL_NET) {
324                 bacnet_mesgtyp =  tvb_get_guint8(tvb, offset);
325                 proto_tree_add_uint_format(bacnet_tree,
326                 hf_bacnet_mesgtyp, tvb, offset, 1, bacnet_mesgtyp,
327                     "Network Layer Message Type: %02x (%s)", bacnet_mesgtyp,
328                     bacnet_mesgtyp_name(bacnet_mesgtyp));
329                     offset ++;
330         }
331         /* Vendor ID
332          * The standard says: "If Bit 7 of the control octet is 1 and
333          * the Message Type field contains a value in the range
334          * X'80' - X'FF', then a Vendor ID field shall be present (...)."
335          * We should not go any further in dissecting the packet if it's
336          * not present, but we don't know about that: No length field...
337          */
338         if ((bacnet_mesgtyp > 0x7f) && (bacnet_control == BAC_CONTROL_NET)) {
339                 proto_tree_add_item(bacnet_tree, hf_bacnet_vendor,
340                         tvb, offset, 2, FALSE);
341                 offset += 2;
342                 /* attention: doesnt work here because of if(tree) */
343                 call_dissector(data_handle,
344                     tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
345         }
346         /* Performance Index (in I-Could-Be-Router-To-Network) */
347         if (bacnet_mesgtyp == BAC_NET_ICB_R) {
348                 proto_tree_add_item(bacnet_tree, hf_bacnet_perf,
349                         tvb, offset, 1, FALSE);
350                 offset ++;
351         }
352         /* Reason, DNET (in Reject-Message-To-Network) */
353         if (bacnet_mesgtyp == BAC_NET_REJ) {
354                 bacnet_rejectreason = tvb_get_guint8(tvb, offset);
355                 proto_tree_add_uint_format(bacnet_tree,
356                         hf_bacnet_rejectreason,
357                         tvb, offset, 1,
358                         bacnet_rejectreason, "Rejection Reason: %d (%s)",
359                         bacnet_rejectreason,
360                         bacnet_rejectreason_name(bacnet_rejectreason));
361                 offset ++;
362                 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
363                         tvb, offset, 2, FALSE);
364                 offset += 2;
365         }
366         /* N*DNET (in Router-Busy-To-Network,Router-Available-To-Network) */
367         if ((bacnet_mesgtyp == BAC_NET_R_BUSY) ||
368             (bacnet_mesgtyp == BAC_NET_R_AVA) || (bacnet_mesgtyp == BAC_NET_IAM_R) ) {
369                 while(tvb_reported_length_remaining(tvb, offset) > 1 ) {
370                         proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
371                                 tvb, offset, 2, FALSE);
372                         offset += 2;
373                 }
374         }
375         /* Initialize-Routing-Table */
376         if ( (bacnet_mesgtyp == BAC_NET_INIT_RTAB) ||
377             (bacnet_mesgtyp == BAC_NET_INIT_RTAB_ACK) ) {
378                 bacnet_rportnum = tvb_get_guint8(tvb, offset);
379                 /* number of ports */
380                 proto_tree_add_uint(bacnet_tree, hf_bacnet_rportnum,
381                         tvb, offset, 1, bacnet_rportnum);
382                 offset ++;
383                 for(i=0; i>bacnet_rportnum; i++) {
384                         /* Connected DNET */
385                         proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
386                                 tvb, offset, 2, FALSE);
387                         offset += 2;
388                         /* Port ID */
389                         proto_tree_add_item(bacnet_tree, hf_bacnet_portid,
390                                 tvb, offset, 1, FALSE);
391                         offset ++;
392                         /* Port Info Length */
393                         bacnet_pinfolen = tvb_get_guint8(tvb, offset);
394                         proto_tree_add_uint(bacnet_tree, hf_bacnet_pinfolen,
395                                 tvb, offset, 1, bacnet_pinfolen);
396                         offset ++;
397                         for(j=0; j>bacnet_pinfolen; j++){
398                             /* Port Info */
399                             proto_tree_add_item(bacnet_tree, hf_bacnet_pinfo,
400                                 tvb, offset, 1, FALSE);
401                             offset ++;
402                         }
403                 }
404         }
405         proto_item_set_len(ti, offset);
406
407 /* dissect BACnet APDU
408  */
409         next_tvb = tvb_new_subset(tvb,offset,-1,-1);
410         if (bacnet_control & BAC_CONTROL_NET) {
411                 /* Unknown function - dissect the payload as data */
412                 call_dissector(data_handle, next_tvb, pinfo, tree);
413         } else {
414                 /* APDU - call the APDU dissector */
415                 call_dissector(bacapp_handle, next_tvb, pinfo, tree);
416         }
417 }
418
419 void
420 proto_register_bacnet(void)
421 {
422         static hf_register_info hf[] = {
423                 { &hf_bacnet_version,
424                         { "Version",           "bacnet.version",
425                         FT_UINT8, BASE_DEC, NULL, 0,
426                         "BACnet Version", HFILL }
427                 },
428                 { &hf_bacnet_control,
429                         { "Control",           "bacnet.control",
430                         FT_UINT8, BASE_HEX, NULL, 0,
431                         "BACnet Control", HFILL }
432                 },
433                 { &hf_bacnet_control_net,
434                         { "NSDU contains",
435                         "bacnet.control_net",
436                         FT_BOOLEAN, 8, TFS(&control_net_set_high),
437                         BAC_CONTROL_NET, "BACnet Control", HFILL }
438                 },
439                 { &hf_bacnet_control_res1,
440                         { "Reserved",
441                         "bacnet.control_res1",
442                         FT_BOOLEAN, 8, TFS(&control_res_high),
443                         BAC_CONTROL_RES1, "BACnet Control", HFILL }
444                 },
445                 { &hf_bacnet_control_dest,
446                         { "Destination Specifier",
447                         "bacnet.control_dest",
448                         FT_BOOLEAN, 8, TFS(&control_dest_high),
449                         BAC_CONTROL_DEST, "BACnet Control", HFILL }
450                 },
451                 { &hf_bacnet_control_res2,
452                         { "Reserved",
453                         "bacnet.control_res2",
454                         FT_BOOLEAN, 8, TFS(&control_res_high),
455                         BAC_CONTROL_RES2, "BACnet Control", HFILL }
456                 },
457                 { &hf_bacnet_control_src,
458                         { "Source specifier",
459                         "bacnet.control_src",
460                         FT_BOOLEAN, 8, TFS(&control_src_high),
461                         BAC_CONTROL_SRC, "BACnet Control", HFILL }
462                 },
463                 { &hf_bacnet_control_expect,
464                         { "Expecting Reply",
465                         "bacnet.control_expect",
466                         FT_BOOLEAN, 8, TFS(&control_expect_high),
467                         BAC_CONTROL_EXPECT, "BACnet Control", HFILL }
468                 },
469                 { &hf_bacnet_control_prio_high,
470                         { "Priority",
471                         "bacnet.control_prio_high",
472                         FT_BOOLEAN, 8, TFS(&control_prio_high_high),
473                         BAC_CONTROL_PRIO_HIGH, "BACnet Control", HFILL }
474                 },
475                 { &hf_bacnet_control_prio_low,
476                         { "Priority",
477                         "bacnet.control_prio_low",
478                         FT_BOOLEAN, 8, TFS(&control_prio_low_high),
479                         BAC_CONTROL_PRIO_LOW, "BACnet Control", HFILL }
480                 },
481                 { &hf_bacnet_dnet,
482                         { "Destination Network Address", "bacnet.dnet",
483                         FT_UINT16, BASE_HEX, NULL, 0,
484                         "Destination Network Address", HFILL }
485                 },
486                 { &hf_bacnet_dlen,
487                         { "Destination MAC Layer Address Length", "bacnet.dlen",
488                         FT_UINT8, BASE_DEC, NULL, 0,
489                         "Destination MAC Layer Address Length", HFILL }
490                 },
491                 { &hf_bacnet_dadr_eth,
492                         { "Destination ISO 8802-3 MAC Address", "bacnet.dadr_eth",
493                         FT_ETHER, BASE_HEX, NULL, 0,
494                         "Destination ISO 8802-3 MAC Address", HFILL }
495                 },
496                 { &hf_bacnet_dadr_tmp,
497                         { "Unknown Destination MAC", "bacnet.dadr_tmp",
498                         FT_BYTES, BASE_HEX, NULL, 0,
499                         "Unknown Destination MAC", HFILL }
500                 },
501                 { &hf_bacnet_snet,
502                         { "Source Network Address", "bacnet.snet",
503                         FT_UINT16, BASE_HEX, NULL, 0,
504                         "Source Network Address", HFILL }
505                 },
506                 { &hf_bacnet_slen,
507                         { "Source MAC Layer Address Length", "bacnet.slen",
508                         FT_UINT8, BASE_DEC, NULL, 0,
509                         "Source MAC Layer Address Length", HFILL }
510                 },
511                 { &hf_bacnet_sadr_eth,
512                         { "SADR", "bacnet.sadr_eth",
513                         FT_ETHER, BASE_HEX, NULL, 0,
514                         "Source ISO 8802-3 MAC Address", HFILL }
515                 },
516                 { &hf_bacnet_sadr_tmp,
517                         { "Unknown Source MAC", "bacnet.sadr_tmp",
518                         FT_BYTES, BASE_HEX, NULL, 0,
519                         "Unknown Source MAC", HFILL }
520                 },
521                 { &hf_bacnet_hopc,
522                         { "Hop Count", "bacnet.hopc",
523                         FT_UINT8, BASE_DEC, NULL, 0,
524                         "Hop Count", HFILL }
525                 },
526                 { &hf_bacnet_mesgtyp,
527                         { "Message Type", "bacnet.mesgtyp",
528                         FT_UINT8, BASE_HEX, NULL, 0,
529                         "Message Type", HFILL }
530                 },
531                 { &hf_bacnet_vendor,
532                         { "Vendor ID", "bacnet.vendor",
533                         FT_UINT16, BASE_HEX, NULL, 0,
534                         "Vendor ID", HFILL }
535                 },
536                 { &hf_bacnet_perf,
537                         { "Performance Index", "bacnet.perf",
538                         FT_UINT8, BASE_DEC, NULL, 0,
539                         "Performance Index", HFILL }
540                 },
541                 { &hf_bacnet_rejectreason,
542                         { "Reject Reason", "bacnet.rejectreason",
543                         FT_UINT8, BASE_DEC, NULL, 0,
544                         "Reject Reason", HFILL }
545                 },
546                 { &hf_bacnet_rportnum,
547                         { "Number of Port Mappings", "bacnet.rportnum",
548                         FT_UINT8, BASE_DEC, NULL, 0,
549                         "Number of Port Mappings", HFILL }
550                 },
551                 { &hf_bacnet_pinfolen,
552                         { "Port Info Length", "bacnet.pinfolen",
553                         FT_UINT8, BASE_DEC, NULL, 0,
554                         "Port Info Length", HFILL }
555                 },
556                 { &hf_bacnet_portid,
557                         { "Port ID", "bacnet.portid",
558                         FT_UINT8, BASE_HEX, NULL, 0,
559                         "Port ID", HFILL }
560                 },
561                 { &hf_bacnet_pinfo,
562                         { "Port Info", "bacnet.pinfo",
563                         FT_UINT8, BASE_HEX, NULL, 0,
564                         "Port Info", HFILL }
565                 },
566         };
567
568         static gint *ett[] = {
569                 &ett_bacnet,
570                 &ett_bacnet_control,
571         };
572
573         proto_bacnet = proto_register_protocol("Building Automation and Control Network NPDU",
574             "BACnet", "bacnet");
575
576         proto_register_field_array(proto_bacnet, hf, array_length(hf));
577         proto_register_subtree_array(ett, array_length(ett));
578
579         register_dissector("bacnet", dissect_bacnet, proto_bacnet);
580 }
581
582 void
583 proto_reg_handoff_bacnet(void)
584 {
585         dissector_handle_t bacnet_handle;
586
587         bacnet_handle = find_dissector("bacnet");
588         dissector_add("bvlc.function", 0x04, bacnet_handle);
589         dissector_add("bvlc.function", 0x09, bacnet_handle);
590         dissector_add("bvlc.function", 0x0a, bacnet_handle);
591         dissector_add("bvlc.function", 0x0b, bacnet_handle);
592         dissector_add("llc.dsap", SAP_BACNET, bacnet_handle);
593         bacapp_handle = find_dissector("bacapp");
594         data_handle = find_dissector("data");
595 }