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