Get rid of some unnecessary settings of "pinfo->current_proto" - if the
[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.3 2001/05/30 07:48:23 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 "packet.h"
51
52 static dissector_table_t bacnet_dissector_table;
53
54 static const char*
55 bacnet_mesgtyp_name (guint8 bacnet_mesgtyp){
56   static const char *type_names[] = {
57         "Who-Is-Router-To-Network",
58         "I-Am-Router-To-Network",
59         "I-Could-Be-Router-To-Network",
60         "Reject-Message-To-Network",
61         "Router-Busy-To-Network",
62         "Router-Available-To-Network",
63         "Initialize-Routing-Table",
64         "Initialize-Routing-Table-Ack",
65         "Establish-Connection-To-Network",
66         "Disconnect-Connection-To-Network"
67         };
68   if(bacnet_mesgtyp < 0x0a) {
69         return type_names[bacnet_mesgtyp];
70   } else {
71         return (bacnet_mesgtyp < 0x80)? "Reserved for Use by ASHRAE" : "Vendor Proprietary Message";
72   }
73 }
74
75 static const char*
76 bacnet_rejectreason_name (guint8 bacnet_rejectreason) {
77   static const char *type_names[] = {
78         "Other error.",
79         "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.",
80         "The router is busy and unable to accept messages for the specified DNET at the present time.",
81         "It is an unknown network layer message type.",
82         "The message is too long to be routed to this DNET.",
83         "The router is no longer directly connected to DNET but can reconnect if requested.",
84         "The router is no longer directly connected to DNET and cannot reconnect even if requested."
85         };
86    return (bacnet_rejectreason > 6)? "Invalid Rejection Reason.":  type_names[bacnet_rejectreason];
87 }
88
89 /* Network Layer Control Information */
90 #define BAC_CONTROL_NET          0x80
91 #define BAC_CONTROL_RES1         0x40
92 #define BAC_CONTROL_DEST         0x20
93 #define BAC_CONTROL_RES2         0x10
94 #define BAC_CONTROL_SRC          0x08
95 #define BAC_CONTROL_EXPECT       0x04
96 #define BAC_CONTROL_PRIO_HIGH    0x02
97 #define BAC_CONTROL_PRIO_LOW     0x01
98
99 /* Network Layer Message Types */
100 #define BAC_NET_WHO_R           0x00
101 #define BAC_NET_IAM_R           0x01
102 #define BAC_NET_ICB_R           0x02
103 #define BAC_NET_REJ             0x03
104 #define BAC_NET_R_BUSY          0x04
105 #define BAC_NET_R_AVA           0x05
106 #define BAC_NET_INIT_RTAB       0x06
107 #define BAC_NET_INIT_RTAB_ACK   0x07
108 #define BAC_NET_EST_CON         0x08
109 #define BAC_NET_DISC_CON        0x09
110
111 static const true_false_string control_net_set_high = {
112         "network layer message, message type field present.",
113         "BACnet APDU, message type field absent."
114 };
115
116 static const true_false_string control_res_high = {
117         "Shall be zero, but is one.",
118         "Shall be zero and is zero."
119 };
120 static const true_false_string control_dest_high = {
121         "DNET, DLEN and Hop Count present. If DLEN=0: broadcast, dest. address field absent.",
122         "DNET, DLEN, DADR and Hop Count absent."
123 };
124  
125 static const true_false_string control_src_high = {
126         "SNET, SLEN and SADR present, SLEN=0 invalid, SLEN specifies length of SADR",
127         "SNET, SLEN and SADR absent"
128 };
129
130 static const true_false_string control_expect_high = {
131         "BACnet-Confirmed-Request-PDU, a segment of BACnet-ComplexACK-PDU or Network Message expecting a reply present.",
132         "Other than a BACnet-Confirmed-Request-PDU, segment of BACnet-ComplexACK-PDU or network layer message expecting a reply present."
133 };
134
135 static const true_false_string control_prio_high_high = {
136         "Life Safety or Critical Equipment message.",
137         "Not a Life Safety or Critical Equipment message."
138 };
139
140 static const true_false_string control_prio_low_high = {
141         "Urgent message",
142         "Normal message"
143 };
144
145
146 static int proto_bacnet = -1;
147 static int hf_bacnet_version = -1;
148 static int hf_bacnet_control = -1;
149 static int hf_bacnet_control_net = -1;
150 static int hf_bacnet_control_res1 = -1;
151 static int hf_bacnet_control_dest = -1;
152 static int hf_bacnet_control_res2 = -1;
153 static int hf_bacnet_control_src = -1;
154 static int hf_bacnet_control_expect = -1;
155 static int hf_bacnet_control_prio_high = -1;
156 static int hf_bacnet_control_prio_low = -1;
157 static int hf_bacnet_dnet = -1;
158 static int hf_bacnet_dlen = -1;
159 static int hf_bacnet_dadr_eth = -1;
160 static int hf_bacnet_dadr_tmp = -1;
161 static int hf_bacnet_snet = -1;
162 static int hf_bacnet_slen = -1;
163 static int hf_bacnet_sadr_eth = -1;
164 static int hf_bacnet_sadr_tmp = -1;
165 static int hf_bacnet_hopc = -1;
166 static int hf_bacnet_mesgtyp = -1;
167 static int hf_bacnet_vendor = -1;
168 static int hf_bacnet_perf = -1;
169 static int hf_bacnet_rejectreason = -1;
170 static int hf_bacnet_rportnum = -1;
171 static int hf_bacnet_portid = -1;
172 static int hf_bacnet_pinfolen = -1;
173 static int hf_bacnet_pinfo = -1;
174
175 static gint ett_bacnet = -1;
176 static gint ett_bacnet_control = -1;
177
178 static void
179 dissect_bacnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
180 {
181         proto_item *ti;
182         proto_item *ct;
183         proto_tree *bacnet_tree;
184         proto_tree *control_tree;
185
186         gint offset;
187         guint8 bacnet_version;
188         guint8 bacnet_control;
189         guint8 bacnet_control_net;
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->fd, COL_PROTOCOL)) 
201                 col_set_str(pinfo->fd, COL_PROTOCOL, "BACnet-NPDU");
202
203         if (check_col(pinfo->fd, COL_INFO)) 
204                 col_set_str(pinfo->fd, 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_control_net = tvb_get_guint8(tvb, offset+1) & BAC_CONTROL_NET;
210         bacnet_dlen = 0;
211         bacnet_slen = 0;
212         bacnet_mesgtyp = 0;
213         bacnet_rejectreason = 0;
214         bacnet_rportnum = 0;
215         bacnet_pinfolen =0;
216         i = 0;
217         j = 0;
218
219         if (tree) {
220
221 /* I don't know the length of the NPDU by know. Setting the length after dissection */
222                 ti = proto_tree_add_item(tree, proto_bacnet, tvb, 0, 0, FALSE);
223
224                 bacnet_tree = proto_item_add_subtree(ti, ett_bacnet);
225
226                 proto_tree_add_uint_format(bacnet_tree, hf_bacnet_version, tvb, 
227                         offset, 1,
228                         bacnet_version,"Version: 0x%02x (%s)",bacnet_version,
229                         (bacnet_version == 0x01)?"ASHRAE 135-1995":"unknown");
230                 offset ++;
231                 ct = proto_tree_add_uint_format(bacnet_tree, hf_bacnet_control, 
232                         tvb, offset, 1,
233                         bacnet_control,"Control: 0x%02x",bacnet_control);
234                 control_tree = proto_item_add_subtree(ct, 
235                         ett_bacnet_control);
236                 proto_tree_add_boolean(control_tree, hf_bacnet_control_net, 
237                         tvb, offset, 1, bacnet_control);
238                 proto_tree_add_boolean(control_tree, hf_bacnet_control_res1, tvb, 
239                         offset, 1, bacnet_control);
240                 proto_tree_add_boolean(control_tree, hf_bacnet_control_dest, tvb, 
241                         offset, 1, bacnet_control);
242                 proto_tree_add_boolean(control_tree, hf_bacnet_control_res2, tvb, 
243                         offset, 1, bacnet_control);
244                 proto_tree_add_boolean(control_tree, hf_bacnet_control_src, tvb, 
245                         offset, 1, bacnet_control);
246                 proto_tree_add_boolean(control_tree, hf_bacnet_control_expect, tvb, 
247                         offset, 1, bacnet_control);
248                 proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_high, 
249                         tvb, offset, 1, bacnet_control);
250                 proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_low, 
251                         tvb, offset, 1, bacnet_control);
252                 offset ++;
253                 if (bacnet_control & BAC_CONTROL_DEST) { /* DNET, DLEN, DADR */
254                         proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
255                                 tvb, offset, 2, FALSE);
256                         offset += 2;
257                         bacnet_dlen = tvb_get_guint8(tvb, offset);
258                         /* DLEN = 0 is broadcast on dest.network */
259                         if( bacnet_dlen == 0) {
260                                 /* append to hf_bacnet_dlen: broadcast */
261                                 proto_tree_add_uint_format(bacnet_tree, 
262                                 hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen, 
263                                 "Destination MAC Layer Address Length: %d indicates Broadcast on Destination Network",
264                                 bacnet_dlen);
265                                 offset ++;
266                                 /* going to SNET */
267                         } else if (bacnet_dlen==6) {
268                                 proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
269                                         tvb, offset, 1, bacnet_dlen);
270                                 offset ++;
271                                 /* Ethernet MAC */
272                                 proto_tree_add_item(bacnet_tree, 
273                                         hf_bacnet_dadr_eth, tvb, offset, 
274                                         bacnet_dlen, FALSE);
275                                 offset += bacnet_dlen;
276                         } else if (bacnet_dlen<7) {
277                                 proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
278                                         tvb, offset, 1, bacnet_dlen);
279                                 offset ++;
280                                 /* Other MAC formats should be included here */
281                                 proto_tree_add_item(bacnet_tree, 
282                                         hf_bacnet_dadr_tmp, tvb, offset, 
283                                         bacnet_dlen, FALSE);
284                                 offset += bacnet_dlen;
285                         } else {
286                                 proto_tree_add_uint_format(bacnet_tree, 
287                                 hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen, 
288                                 "Destination MAC Layer Address Length: %d invalid!",
289                                 bacnet_dlen);
290                         }
291                 }
292                 if (bacnet_control & BAC_CONTROL_SRC) { /* SNET, SLEN, SADR */
293                         /* SNET */
294                         proto_tree_add_uint(bacnet_tree, hf_bacnet_snet,
295                                 tvb, offset, 2, tvb_get_ntohs(tvb, offset));
296                         offset += 2;
297                         bacnet_slen = tvb_get_guint8(tvb, offset);
298                         if( bacnet_slen == 0) { /* SLEN = 0 invalid */
299                                 proto_tree_add_uint_format(bacnet_tree,
300                                 hf_bacnet_slen, tvb, offset, 1, bacnet_slen, 
301                                 "Source MAC Layer Address Length: %d invalid!",
302                                 bacnet_slen);
303                                 offset ++;
304                         } else if (bacnet_slen==6) {
305                                 /* SLEN */
306                                  proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
307                                         tvb, offset, 1, bacnet_slen);
308                                 offset ++;
309                                 /* Ethernet MAC */
310                                 proto_tree_add_item(bacnet_tree, 
311                                         hf_bacnet_sadr_eth, tvb, offset, 
312                                         bacnet_slen, FALSE);
313                                 offset += bacnet_slen;
314                         } else if (bacnet_slen<6) { /* LON,ARCNET,MS/TP MAC */
315                                 /* SLEN */
316                                  proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
317                                         tvb, offset, 1, bacnet_slen);
318                                 offset ++;
319                                 /* Other MAC formats should be included here */
320                                 proto_tree_add_item(bacnet_tree, 
321                                         hf_bacnet_sadr_tmp, tvb, offset, 
322                                         bacnet_slen, FALSE);
323                                 offset += bacnet_slen;
324                         } else {
325                                 proto_tree_add_uint_format(bacnet_tree,
326                                 hf_bacnet_slen, tvb, offset, 1, bacnet_slen, 
327                                 "Source MAC Layer Address Length: %d invalid!",
328                                 bacnet_slen);
329                                 offset ++;
330                         }
331                 }
332                 if (bacnet_control & BAC_CONTROL_DEST) { /* Hopcount */
333                         proto_tree_add_item(bacnet_tree, hf_bacnet_hopc,
334                                 tvb, offset, 1, FALSE);
335                         offset ++;
336                 }
337                 /* Network Layer Message Type */
338                 if (bacnet_control & BAC_CONTROL_NET) { 
339                         bacnet_mesgtyp =  tvb_get_guint8(tvb, offset);
340                         proto_tree_add_uint_format(bacnet_tree,
341                         hf_bacnet_mesgtyp, tvb, offset, 1, bacnet_mesgtyp,
342                         "Network Layer Message Type: %02x (%s)", bacnet_mesgtyp,
343                         bacnet_mesgtyp_name(bacnet_mesgtyp));
344                         offset ++;
345                 }
346                 /* Vendor ID 
347                  * The standard says: "If Bit 7 of the control octet is 1 and 
348                  * the Message Type field contains a value in the range 
349                  * X'80' - X'FF', then a Vendor ID field shall be present (...)."
350                  * We should not go any further in dissecting the packet if it's
351                  * not present, but we don't know about that: No length field...
352                  */
353                 if ((bacnet_mesgtyp > 0x7f) && (bacnet_control == BAC_CONTROL_NET)) {
354                         proto_tree_add_item(bacnet_tree, hf_bacnet_vendor,
355                                 tvb, offset, 2, FALSE);
356                         offset += 2;
357                         /* attention: doesnt work here because of if(tree) */
358                         dissect_data(tvb, offset, pinfo, tree);
359                 }
360                 /* Performance Index (in I-Could-Be-Router-To-Network) */
361                 if (bacnet_mesgtyp == BAC_NET_ICB_R) {
362                         proto_tree_add_item(bacnet_tree, hf_bacnet_perf,
363                                 tvb, offset, 1, FALSE);
364                         offset ++;
365                 }
366                 /* Reason, DNET (in Reject-Message-To-Network) */
367                 if (bacnet_mesgtyp == BAC_NET_REJ) {
368                         bacnet_rejectreason = tvb_get_guint8(tvb, offset);
369                         proto_tree_add_uint_format(bacnet_tree, 
370                                 hf_bacnet_rejectreason,
371                                 tvb, offset, 1, 
372                                 bacnet_rejectreason, "Rejection Reason: %d (%s)",
373                                 bacnet_rejectreason,
374                                 bacnet_rejectreason_name(bacnet_rejectreason));
375                         offset ++;
376                         proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
377                                 tvb, offset, 2, FALSE);
378                         offset += 2;
379                 }
380                 /* N*DNET (in Router-Busy-To-Network,Router-Available-To-Network) */
381                 if ((bacnet_mesgtyp == BAC_NET_R_BUSY) || 
382                 (bacnet_mesgtyp == BAC_NET_R_AVA) || (bacnet_mesgtyp == BAC_NET_IAM_R) ) {
383                     while(tvb_reported_length_remaining(tvb, offset) > 1 ) {
384                         proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
385                                 tvb, offset, 2, FALSE);
386                         offset += 2;
387                     }
388                 }
389                 /* Initialize-Routing-Table */
390                 if ( (bacnet_mesgtyp == BAC_NET_INIT_RTAB) || 
391                     (bacnet_mesgtyp == BAC_NET_INIT_RTAB_ACK) ) {
392                     bacnet_rportnum = tvb_get_guint8(tvb, offset);
393                     /* number of ports */
394                     proto_tree_add_uint(bacnet_tree, hf_bacnet_rportnum,
395                         tvb, offset, 1, bacnet_rportnum);
396                     offset ++;
397                     for(i=0; i>bacnet_rportnum; i++) {
398                         /* Connected DNET */
399                         proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
400                                 tvb, offset, 2, FALSE);
401                         offset += 2;
402                         /* Port ID */
403                         proto_tree_add_item(bacnet_tree, hf_bacnet_portid,
404                                 tvb, offset, 1, FALSE);
405                         offset ++;
406                         /* Port Info Length */
407                         bacnet_pinfolen = tvb_get_guint8(tvb, offset);
408                         proto_tree_add_uint(bacnet_tree, hf_bacnet_pinfolen,
409                                 tvb, offset, 1, bacnet_pinfolen);
410                         offset ++;
411                         for(j=0; j>bacnet_pinfolen; j++){
412                             /* Port Info */
413                             proto_tree_add_item(bacnet_tree, hf_bacnet_pinfo,
414                                 tvb, offset, 1, FALSE);
415                             offset ++;
416                         }
417                     }
418                     
419                 }
420                 proto_item_set_len(ti, offset);
421         }
422
423 /* dissect BACnet APDU
424  */
425         next_tvb = tvb_new_subset(tvb,offset,-1,-1);
426         /* Code from Guy Harris */
427         if (!dissector_try_port(bacnet_dissector_table,
428         bacnet_control_net, next_tvb, pinfo, tree)) {
429                 /* Unknown function - dissect the payload as data */
430                 dissect_data(next_tvb, 0, 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" }
442                 },
443                 { &hf_bacnet_control,
444                         { "Control",           "bacnet.control",
445                         FT_UINT8, BASE_HEX, NULL, 0xff,
446                         "BACnet Control" }
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" }
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" }
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" }
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" }
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" }
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" }
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" }
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" }
495                 },
496                 { &hf_bacnet_dnet,
497                         { "Destination Network Address", "bacnet.dnet",
498                         FT_UINT16, BASE_HEX, NULL, 0,
499                         "Destination Network Address" }
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" }
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" }
510                 },
511                 { &hf_bacnet_dadr_tmp,
512                         { "Unknown Destination MAC", "bacnet.dadr_tmp",
513                         FT_BYTES, BASE_HEX, NULL, 0,
514                         "Unknown Destination MAC" }
515                 },
516                 { &hf_bacnet_snet,
517                         { "Source Network Address", "bacnet.snet",
518                         FT_UINT16, BASE_HEX, NULL, 0,
519                         "Source Network Address" }
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" }
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" }
530                 },
531                 { &hf_bacnet_sadr_tmp,
532                         { "Unknown Source MAC", "bacnet.sadr_tmp",
533                         FT_BYTES, BASE_HEX, NULL, 0,
534                         "Unknown Source MAC" }
535                 },
536                 { &hf_bacnet_hopc,
537                         { "Hop Count", "bacnet.hopc",
538                         FT_UINT8, BASE_DEC, NULL, 0,
539                         "Hop Count" }
540                 },
541                 { &hf_bacnet_mesgtyp,
542                         { "Message Type", "bacnet.mesgtyp",
543                         FT_UINT8, BASE_HEX, NULL, 0,
544                         "Message Type" }
545                 },
546                 { &hf_bacnet_vendor,
547                         { "Vendor ID", "bacnet.vendor",
548                         FT_UINT16, BASE_HEX, NULL, 0,
549                         "Vendor ID" }
550                 },
551                 { &hf_bacnet_perf,
552                         { "Performance Index", "bacnet.perf",
553                         FT_UINT8, BASE_DEC, NULL, 0,
554                         "Performance Index" }
555                 },
556                 { &hf_bacnet_rejectreason,
557                         { "Reject Reason", "bacnet.rejectreason",
558                         FT_UINT8, BASE_DEC, NULL, 0,
559                         "Reject Reason" }
560                 },
561                 { &hf_bacnet_rportnum,
562                         { "Number of Port Mappings", "bacnet.rportnum",
563                         FT_UINT8, BASE_DEC, NULL, 0,
564                         "Number of Port Mappings" }
565                 },
566                 { &hf_bacnet_pinfolen,
567                         { "Port Info Length", "bacnet.pinfolen",
568                         FT_UINT8, BASE_DEC, NULL, 0,
569                         "Port Info Length" }
570                 },
571                 { &hf_bacnet_portid,
572                         { "Port ID", "bacnet.portid",
573                         FT_UINT8, BASE_HEX, NULL, 0,
574                         "Port ID" }
575                 },
576                 { &hf_bacnet_pinfo,
577                         { "Port Info", "bacnet.pinfo",
578                         FT_UINT8, BASE_HEX, NULL, 0,
579                         "Port Info" }
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         bacnet_dissector_table = register_dissector_table("bacnet_control_net");
596 }
597
598 void
599 proto_reg_handoff_bacnet(void)
600 {
601         dissector_add("bvlc.function", 0x04, dissect_bacnet, proto_bacnet);
602         dissector_add("bvlc.function", 0x09, dissect_bacnet, proto_bacnet);
603         dissector_add("bvlc.function", 0x0a, dissect_bacnet, proto_bacnet);
604         dissector_add("bvlc.function", 0x0b, dissect_bacnet, proto_bacnet);
605 }