2 * Routines for BACnet (NPDU) dissection
3 * Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
4 * Enhanced by Steve Karg, 2005, <skarg@users.sourceforge.net>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * Copied from README.developer,v 1.23
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 #include <epan/packet.h>
41 #include <epan/llcsaps.h>
43 static dissector_handle_t bacapp_handle;
44 static dissector_handle_t data_handle;
47 bacnet_mesgtyp_name (guint8 bacnet_mesgtyp){
48 static const char *type_names[] = {
49 "Who-Is-Router-To-Network",
50 "I-Am-Router-To-Network",
51 "I-Could-Be-Router-To-Network",
52 "Reject-Message-To-Network",
53 "Router-Busy-To-Network",
54 "Router-Available-To-Network",
55 "Initialize-Routing-Table",
56 "Initialize-Routing-Table-Ack",
57 "Establish-Connection-To-Network",
58 "Disconnect-Connection-To-Network"
60 if(bacnet_mesgtyp < 0x0a) {
61 return type_names[bacnet_mesgtyp];
63 return (bacnet_mesgtyp < 0x80)? "Reserved for Use by ASHRAE" : "Vendor Proprietary Message";
68 bacnet_rejectreason_name (guint8 bacnet_rejectreason) {
69 static const char *type_names[] = {
71 "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.",
72 "The router is busy and unable to accept messages for the specified DNET at the present time.",
73 "It is an unknown network layer message type.",
74 "The message is too long to be routed to this DNET.",
75 "The router is no longer directly connected to DNET but can reconnect if requested.",
76 "The router is no longer directly connected to DNET and cannot reconnect even if requested."
78 return (bacnet_rejectreason > 6)? "Invalid Rejection Reason.": type_names[bacnet_rejectreason];
81 /* Network Layer Control Information */
82 #define BAC_CONTROL_NET 0x80
83 #define BAC_CONTROL_RES1 0x40
84 #define BAC_CONTROL_DEST 0x20
85 #define BAC_CONTROL_RES2 0x10
86 #define BAC_CONTROL_SRC 0x08
87 #define BAC_CONTROL_EXPECT 0x04
88 #define BAC_CONTROL_PRIO_HIGH 0x02
89 #define BAC_CONTROL_PRIO_LOW 0x01
91 /* Network Layer Message Types */
92 #define BAC_NET_WHO_R 0x00
93 #define BAC_NET_IAM_R 0x01
94 #define BAC_NET_ICB_R 0x02
95 #define BAC_NET_REJ 0x03
96 #define BAC_NET_R_BUSY 0x04
97 #define BAC_NET_R_AVA 0x05
98 #define BAC_NET_INIT_RTAB 0x06
99 #define BAC_NET_INIT_RTAB_ACK 0x07
100 #define BAC_NET_EST_CON 0x08
101 #define BAC_NET_DISC_CON 0x09
103 static const true_false_string control_net_set_high = {
104 "network layer message, message type field present.",
105 "BACnet APDU, message type field absent."
108 static const true_false_string control_res_high = {
109 "Shall be zero, but is one.",
110 "Shall be zero and is zero."
112 static const true_false_string control_dest_high = {
113 "DNET, DLEN and Hop Count present. If DLEN=0: broadcast, dest. address field absent.",
114 "DNET, DLEN, DADR and Hop Count absent."
117 static const true_false_string control_src_high = {
118 "SNET, SLEN and SADR present, SLEN=0 invalid, SLEN specifies length of SADR",
119 "SNET, SLEN and SADR absent"
122 static const true_false_string control_expect_high = {
123 "BACnet-Confirmed-Request-PDU, a segment of BACnet-ComplexACK-PDU or Network Message expecting a reply present.",
124 "Other than a BACnet-Confirmed-Request-PDU, segment of BACnet-ComplexACK-PDU or network layer message expecting a reply present."
127 static const true_false_string control_prio_high_high = {
128 "Life Safety or Critical Equipment message.",
129 "Not a Life Safety or Critical Equipment message."
132 static const true_false_string control_prio_low_high = {
138 static int proto_bacnet = -1;
139 static int hf_bacnet_version = -1;
140 static int hf_bacnet_control = -1;
141 static int hf_bacnet_control_net = -1;
142 static int hf_bacnet_control_res1 = -1;
143 static int hf_bacnet_control_dest = -1;
144 static int hf_bacnet_control_res2 = -1;
145 static int hf_bacnet_control_src = -1;
146 static int hf_bacnet_control_expect = -1;
147 static int hf_bacnet_control_prio_high = -1;
148 static int hf_bacnet_control_prio_low = -1;
149 static int hf_bacnet_dnet = -1;
150 static int hf_bacnet_dlen = -1;
151 static int hf_bacnet_dadr_eth = -1;
152 static int hf_bacnet_dadr_mstp = -1;
153 static int hf_bacnet_dadr_tmp = -1;
154 static int hf_bacnet_snet = -1;
155 static int hf_bacnet_slen = -1;
156 static int hf_bacnet_sadr_eth = -1;
157 static int hf_bacnet_sadr_mstp = -1;
158 static int hf_bacnet_sadr_tmp = -1;
159 static int hf_bacnet_hopc = -1;
160 static int hf_bacnet_mesgtyp = -1;
161 static int hf_bacnet_vendor = -1;
162 static int hf_bacnet_perf = -1;
163 static int hf_bacnet_rejectreason = -1;
164 static int hf_bacnet_rportnum = -1;
165 static int hf_bacnet_portid = -1;
166 static int hf_bacnet_pinfolen = -1;
167 static int hf_bacnet_term_time_value = -1;
169 static gint ett_bacnet = -1;
170 static gint ett_bacnet_control = -1;
173 dissect_bacnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
177 proto_tree *bacnet_tree;
178 proto_tree *control_tree;
181 guint8 bacnet_version;
182 guint8 bacnet_control;
185 guint8 bacnet_mesgtyp;
186 guint8 bacnet_rejectreason;
187 guint8 bacnet_rportnum;
188 guint8 bacnet_pinfolen;
193 if (check_col(pinfo->cinfo, COL_PROTOCOL))
194 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet-NPDU");
196 if (check_col(pinfo->cinfo, COL_INFO))
197 col_set_str(pinfo->cinfo, COL_INFO, "Building Automation and Control Network NPDU");
200 bacnet_version = tvb_get_guint8(tvb, offset);
201 bacnet_control = tvb_get_guint8(tvb, offset+1);
205 bacnet_rejectreason = 0;
211 /* I don't know the length of the NPDU by now. Setting the length after dissection */
212 ti = proto_tree_add_item(tree, proto_bacnet, tvb, 0, -1, FALSE);
214 bacnet_tree = proto_item_add_subtree(ti, ett_bacnet);
216 proto_tree_add_uint_format_value(bacnet_tree, hf_bacnet_version, tvb,
218 bacnet_version,"0x%02x (%s)",bacnet_version,
219 (bacnet_version == 0x01)?"ASHRAE 135-1995":"unknown");
221 ct = proto_tree_add_uint(bacnet_tree, hf_bacnet_control,
222 tvb, offset, 1, bacnet_control);
223 control_tree = proto_item_add_subtree(ct, ett_bacnet_control);
224 proto_tree_add_boolean(control_tree, hf_bacnet_control_net,
225 tvb, offset, 1, bacnet_control);
226 proto_tree_add_boolean(control_tree, hf_bacnet_control_res1, tvb,
227 offset, 1, bacnet_control);
228 proto_tree_add_boolean(control_tree, hf_bacnet_control_dest, tvb,
229 offset, 1, bacnet_control);
230 proto_tree_add_boolean(control_tree, hf_bacnet_control_res2, tvb,
231 offset, 1, bacnet_control);
232 proto_tree_add_boolean(control_tree, hf_bacnet_control_src, tvb,
233 offset, 1, bacnet_control);
234 proto_tree_add_boolean(control_tree, hf_bacnet_control_expect, tvb,
235 offset, 1, bacnet_control);
236 proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_high,
237 tvb, offset, 1, bacnet_control);
238 proto_tree_add_boolean(control_tree, hf_bacnet_control_prio_low,
239 tvb, offset, 1, bacnet_control);
241 if (bacnet_control & BAC_CONTROL_DEST) { /* DNET, DLEN, DADR */
242 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
243 tvb, offset, 2, FALSE);
245 bacnet_dlen = tvb_get_guint8(tvb, offset);
246 /* DLEN = 0 is broadcast on dest.network */
247 if( bacnet_dlen == 0) {
248 /* append to hf_bacnet_dlen: broadcast */
249 proto_tree_add_uint_format_value(bacnet_tree,
250 hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen,
251 "%d indicates Broadcast on Destination Network",
255 } else if (bacnet_dlen==6) {
256 proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
257 tvb, offset, 1, bacnet_dlen);
260 proto_tree_add_item(bacnet_tree,
261 hf_bacnet_dadr_eth, tvb, offset,
263 offset += bacnet_dlen;
264 } else if (bacnet_dlen==1) {
265 proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
266 tvb, offset, 1, bacnet_dlen);
268 /* MS/TP or ARCNET MAC */
269 proto_tree_add_item(bacnet_tree,
270 hf_bacnet_dadr_mstp, tvb, offset,
272 offset += bacnet_dlen;
273 } else if (bacnet_dlen<7) {
274 proto_tree_add_uint(bacnet_tree, hf_bacnet_dlen,
275 tvb, offset, 1, bacnet_dlen);
277 /* Other MAC formats should be included here */
278 proto_tree_add_item(bacnet_tree,
279 hf_bacnet_dadr_tmp, tvb, offset,
281 offset += bacnet_dlen;
283 proto_tree_add_uint_format_value(bacnet_tree,
284 hf_bacnet_dlen, tvb, offset, 1, bacnet_dlen,
289 if (bacnet_control & BAC_CONTROL_SRC) { /* SNET, SLEN, SADR */
291 proto_tree_add_uint(bacnet_tree, hf_bacnet_snet,
292 tvb, offset, 2, tvb_get_ntohs(tvb, offset));
294 bacnet_slen = tvb_get_guint8(tvb, offset);
295 if( bacnet_slen == 0) { /* SLEN = 0 invalid */
296 proto_tree_add_uint_format_value(bacnet_tree,
297 hf_bacnet_slen, tvb, offset, 1, bacnet_slen,
301 } else if (bacnet_slen==6) {
303 proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
304 tvb, offset, 1, bacnet_slen);
307 proto_tree_add_item(bacnet_tree,
308 hf_bacnet_sadr_eth, tvb, offset,
310 offset += bacnet_slen;
311 } else if (bacnet_slen==1) {
313 proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
314 tvb, offset, 1, bacnet_slen);
316 /* MS/TP or ARCNET MAC */
317 proto_tree_add_item(bacnet_tree,
318 hf_bacnet_sadr_mstp, tvb, offset,
320 offset += bacnet_slen;
321 } else if (bacnet_slen<6) { /* LON MAC */
323 proto_tree_add_uint(bacnet_tree, hf_bacnet_slen,
324 tvb, offset, 1, bacnet_slen);
326 /* Other MAC formats should be included here */
327 proto_tree_add_item(bacnet_tree,
328 hf_bacnet_sadr_tmp, tvb, offset,
330 offset += bacnet_slen;
332 proto_tree_add_uint_format_value(bacnet_tree,
333 hf_bacnet_slen, tvb, offset, 1, bacnet_slen,
339 if (bacnet_control & BAC_CONTROL_DEST) { /* Hopcount */
340 proto_tree_add_item(bacnet_tree, hf_bacnet_hopc,
341 tvb, offset, 1, FALSE);
344 /* Network Layer Message Type */
345 if (bacnet_control & BAC_CONTROL_NET) {
346 bacnet_mesgtyp = tvb_get_guint8(tvb, offset);
347 proto_tree_add_uint_format_value(bacnet_tree,
348 hf_bacnet_mesgtyp, tvb, offset, 1, bacnet_mesgtyp,
349 "%02x (%s)", bacnet_mesgtyp,
350 bacnet_mesgtyp_name(bacnet_mesgtyp));
351 /* Put the NPDU Type in the info column */
352 if (check_col(pinfo->cinfo, COL_INFO))
354 col_clear(pinfo->cinfo, COL_INFO);
355 col_add_str(pinfo->cinfo, COL_INFO,
356 bacnet_mesgtyp_name(bacnet_mesgtyp));
360 * The standard says: "If Bit 7 of the control octet is 1 and
361 * the Message Type field contains a value in the range
362 * X'80' - X'FF', then a Vendor ID field shall be present (...)."
363 * We should not go any further in dissecting the packet if it's
364 * not present, but we don't know about that: No length field...
366 if (bacnet_mesgtyp > 0x7f) {
367 proto_tree_add_item(bacnet_tree, hf_bacnet_vendor,
368 tvb, offset, 2, FALSE);
370 /* attention: doesnt work here because of if(tree) */
371 call_dissector(data_handle,
372 tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
374 /* Performance Index (in I-Could-Be-Router-To-Network) */
375 if (bacnet_mesgtyp == BAC_NET_ICB_R) {
376 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
377 tvb, offset, 2, FALSE);
379 proto_tree_add_item(bacnet_tree, hf_bacnet_perf,
380 tvb, offset, 1, FALSE);
383 /* Reason, DNET (in Reject-Message-To-Network) */
384 if (bacnet_mesgtyp == BAC_NET_REJ) {
385 bacnet_rejectreason = tvb_get_guint8(tvb, offset);
386 proto_tree_add_uint_format_value(bacnet_tree,
387 hf_bacnet_rejectreason,
389 bacnet_rejectreason, "%d (%s)",
391 bacnet_rejectreason_name(bacnet_rejectreason));
393 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
394 tvb, offset, 2, FALSE);
397 /* N*DNET (in Router-Busy-To-Network,Router-Available-To-Network) */
398 if ((bacnet_mesgtyp == BAC_NET_R_BUSY) ||
399 (bacnet_mesgtyp == BAC_NET_WHO_R) ||
400 (bacnet_mesgtyp == BAC_NET_R_AVA) ||
401 (bacnet_mesgtyp == BAC_NET_IAM_R) ) {
402 while(tvb_reported_length_remaining(tvb, offset) > 1 ) {
403 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
404 tvb, offset, 2, FALSE);
408 /* Initialize-Routing-Table */
409 if ( (bacnet_mesgtyp == BAC_NET_INIT_RTAB) ||
410 (bacnet_mesgtyp == BAC_NET_INIT_RTAB_ACK) ) {
411 bacnet_rportnum = tvb_get_guint8(tvb, offset);
412 /* number of ports */
413 proto_tree_add_uint(bacnet_tree, hf_bacnet_rportnum,
414 tvb, offset, 1, bacnet_rportnum);
416 for(i=0; i<bacnet_rportnum; i++) {
418 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
419 tvb, offset, 2, FALSE);
422 proto_tree_add_item(bacnet_tree, hf_bacnet_portid,
423 tvb, offset, 1, FALSE);
425 /* Port Info Length */
426 bacnet_pinfolen = tvb_get_guint8(tvb, offset);
427 proto_tree_add_uint(bacnet_tree, hf_bacnet_pinfolen,
428 tvb, offset, 1, bacnet_pinfolen);
430 proto_tree_add_text(bacnet_tree, tvb, offset,
431 bacnet_pinfolen, "Port Info: %s",
432 tvb_bytes_to_str(tvb, offset, bacnet_pinfolen));
433 offset += bacnet_pinfolen;
436 /* Establish-Connection-To-Network */
437 if (bacnet_mesgtyp == BAC_NET_EST_CON) {
438 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
439 tvb, offset, 2, FALSE);
441 proto_tree_add_item(bacnet_tree, hf_bacnet_term_time_value,
442 tvb, offset, 1, FALSE);
445 /* Disconnect-Connection-To-Network */
446 if (bacnet_mesgtyp == BAC_NET_DISC_CON) {
447 proto_tree_add_item(bacnet_tree, hf_bacnet_dnet,
448 tvb, offset, 2, FALSE);
451 proto_item_set_len(ti, offset);
453 /* dissect BACnet APDU */
454 next_tvb = tvb_new_subset(tvb,offset,-1,-1);
455 if (bacnet_control & BAC_CONTROL_NET) {
456 /* Unknown function - dissect the payload as data */
457 call_dissector(data_handle, next_tvb, pinfo, tree);
459 /* APDU - call the APDU dissector */
460 call_dissector(bacapp_handle, next_tvb, pinfo, tree);
465 proto_register_bacnet(void)
467 static hf_register_info hf[] = {
468 { &hf_bacnet_version,
469 { "Version", "bacnet.version",
470 FT_UINT8, BASE_DEC, NULL, 0,
471 "BACnet Version", HFILL }
473 { &hf_bacnet_control,
474 { "Control", "bacnet.control",
475 FT_UINT8, BASE_HEX, NULL, 0,
476 "BACnet Control", HFILL }
478 { &hf_bacnet_control_net,
480 "bacnet.control_net",
481 FT_BOOLEAN, 8, TFS(&control_net_set_high),
482 BAC_CONTROL_NET, "BACnet Control", HFILL }
484 { &hf_bacnet_control_res1,
486 "bacnet.control_res1",
487 FT_BOOLEAN, 8, TFS(&control_res_high),
488 BAC_CONTROL_RES1, "BACnet Control", HFILL }
490 { &hf_bacnet_control_dest,
491 { "Destination Specifier",
492 "bacnet.control_dest",
493 FT_BOOLEAN, 8, TFS(&control_dest_high),
494 BAC_CONTROL_DEST, "BACnet Control", HFILL }
496 { &hf_bacnet_control_res2,
498 "bacnet.control_res2",
499 FT_BOOLEAN, 8, TFS(&control_res_high),
500 BAC_CONTROL_RES2, "BACnet Control", HFILL }
502 { &hf_bacnet_control_src,
503 { "Source specifier",
504 "bacnet.control_src",
505 FT_BOOLEAN, 8, TFS(&control_src_high),
506 BAC_CONTROL_SRC, "BACnet Control", HFILL }
508 { &hf_bacnet_control_expect,
510 "bacnet.control_expect",
511 FT_BOOLEAN, 8, TFS(&control_expect_high),
512 BAC_CONTROL_EXPECT, "BACnet Control", HFILL }
514 { &hf_bacnet_control_prio_high,
516 "bacnet.control_prio_high",
517 FT_BOOLEAN, 8, TFS(&control_prio_high_high),
518 BAC_CONTROL_PRIO_HIGH, "BACnet Control", HFILL }
520 { &hf_bacnet_control_prio_low,
522 "bacnet.control_prio_low",
523 FT_BOOLEAN, 8, TFS(&control_prio_low_high),
524 BAC_CONTROL_PRIO_LOW, "BACnet Control", HFILL }
527 { "Destination Network Address", "bacnet.dnet",
528 FT_UINT16, BASE_DEC, NULL, 0,
529 "Destination Network Address", HFILL }
532 { "Destination MAC Layer Address Length", "bacnet.dlen",
533 FT_UINT8, BASE_DEC, NULL, 0,
534 "Destination MAC Layer Address Length", HFILL }
536 { &hf_bacnet_dadr_eth,
537 { "Destination ISO 8802-3 MAC Address", "bacnet.dadr_eth",
538 FT_ETHER, BASE_HEX, NULL, 0,
539 "Destination ISO 8802-3 MAC Address", HFILL }
541 { &hf_bacnet_dadr_mstp,
542 { "DADR", "bacnet.dadr_mstp",
543 FT_UINT8, BASE_DEC, NULL, 0,
544 "Destination MS/TP or ARCNET MAC Address", HFILL }
546 { &hf_bacnet_dadr_tmp,
547 { "Unknown Destination MAC", "bacnet.dadr_tmp",
548 FT_BYTES, BASE_HEX, NULL, 0,
549 "Unknown Destination MAC", HFILL }
552 { "Source Network Address", "bacnet.snet",
553 FT_UINT16, BASE_DEC, NULL, 0,
554 "Source Network Address", HFILL }
557 { "Source MAC Layer Address Length", "bacnet.slen",
558 FT_UINT8, BASE_DEC, NULL, 0,
559 "Source MAC Layer Address Length", HFILL }
561 { &hf_bacnet_sadr_eth,
562 { "SADR", "bacnet.sadr_eth",
563 FT_ETHER, BASE_HEX, NULL, 0,
564 "Source ISO 8802-3 MAC Address", HFILL }
566 { &hf_bacnet_sadr_mstp,
567 { "SADR", "bacnet.sadr_mstp",
568 FT_UINT8, BASE_DEC, NULL, 0,
569 "Source MS/TP or ARCNET MAC Address", HFILL }
571 { &hf_bacnet_sadr_tmp,
572 { "Unknown Source MAC", "bacnet.sadr_tmp",
573 FT_BYTES, BASE_HEX, NULL, 0,
574 "Unknown Source MAC", HFILL }
577 { "Hop Count", "bacnet.hopc",
578 FT_UINT8, BASE_DEC, NULL, 0,
581 { &hf_bacnet_mesgtyp,
582 { "Network Layer Message Type", "bacnet.mesgtyp",
583 FT_UINT8, BASE_HEX, NULL, 0,
584 "Network Layer Message Type", HFILL }
587 { "Vendor ID", "bacnet.vendor",
588 FT_UINT16, BASE_DEC, NULL, 0,
592 { "Performance Index", "bacnet.perf",
593 FT_UINT8, BASE_DEC, NULL, 0,
594 "Performance Index", HFILL }
596 { &hf_bacnet_rejectreason,
597 { "Reject Reason", "bacnet.rejectreason",
598 FT_UINT8, BASE_DEC, NULL, 0,
599 "Reject Reason", HFILL }
601 { &hf_bacnet_rportnum,
602 { "Number of Port Mappings", "bacnet.rportnum",
603 FT_UINT8, BASE_DEC, NULL, 0,
604 "Number of Port Mappings", HFILL }
606 { &hf_bacnet_pinfolen,
607 { "Port Info Length", "bacnet.pinfolen",
608 FT_UINT8, BASE_DEC, NULL, 0,
609 "Port Info Length", HFILL }
612 { "Port ID", "bacnet.portid",
613 FT_UINT8, BASE_HEX, NULL, 0,
616 { &hf_bacnet_term_time_value,
617 { "Termination Time Value (seconds)", "bacnet.term_time_value",
618 FT_UINT8, BASE_DEC, NULL, 0,
619 "Termination Time Value", HFILL }
623 static gint *ett[] = {
628 proto_bacnet = proto_register_protocol("Building Automation and Control Network NPDU",
631 proto_register_field_array(proto_bacnet, hf, array_length(hf));
632 proto_register_subtree_array(ett, array_length(ett));
634 register_dissector("bacnet", dissect_bacnet, proto_bacnet);
638 proto_reg_handoff_bacnet(void)
640 dissector_handle_t bacnet_handle;
642 bacnet_handle = find_dissector("bacnet");
643 dissector_add("bvlc.function", 0x04, bacnet_handle);
644 dissector_add("bvlc.function", 0x09, bacnet_handle);
645 dissector_add("bvlc.function", 0x0a, bacnet_handle);
646 dissector_add("bvlc.function", 0x0b, bacnet_handle);
647 dissector_add("llc.dsap", SAP_BACNET, bacnet_handle);
648 bacapp_handle = find_dissector("bacapp");
649 data_handle = find_dissector("data");