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