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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <epan/packet.h>
35 #include <epan/llcsaps.h>
37 void proto_register_bacnet(void);
38 void proto_reg_handoff_bacnet(void);
40 static dissector_handle_t bacapp_handle
;
41 static dissector_handle_t data_handle
;
42 /* Defined to allow vendor identifier registration of private transfer dissectors */
43 static dissector_table_t bacnet_dissector_table
;
46 bacnet_mesgtyp_name (guint8 bacnet_mesgtyp
){
47 static const char *type_names
[] = {
48 "Who-Is-Router-To-Network",
49 "I-Am-Router-To-Network",
50 "I-Could-Be-Router-To-Network",
51 "Reject-Message-To-Network",
52 "Router-Busy-To-Network",
53 "Router-Available-To-Network",
54 "Initialize-Routing-Table",
55 "Initialize-Routing-Table-Ack",
56 "Establish-Connection-To-Network",
57 "Disconnect-Connection-To-Network"
59 if(bacnet_mesgtyp
< 0x0a) {
60 return type_names
[bacnet_mesgtyp
];
62 return (bacnet_mesgtyp
< 0x80)? "Reserved for Use by ASHRAE" : "Vendor Proprietary Message";
67 bacnet_rejectreason_name (guint8 bacnet_rejectreason
) {
68 static const char *type_names
[] = {
70 "The router is not directly connected to DNET and cannot find a router to DNET on any directly connected network using Who-Is-Router-To-Network messages.",
71 "The router is busy and unable to accept messages for the specified DNET at the present time.",
72 "It is an unknown network layer message type.",
73 "The message is too long to be routed to this DNET.",
74 "The router is no longer directly connected to DNET but can reconnect if requested.",
75 "The router is no longer directly connected to DNET and cannot reconnect even if requested."
77 return (bacnet_rejectreason
> 6)? "Invalid Rejection Reason.": type_names
[bacnet_rejectreason
];
80 /* Network Layer Control Information */
81 #define BAC_CONTROL_NET 0x80
82 #define BAC_CONTROL_RES1 0x40
83 #define BAC_CONTROL_DEST 0x20
84 #define BAC_CONTROL_RES2 0x10
85 #define BAC_CONTROL_SRC 0x08
86 #define BAC_CONTROL_EXPECT 0x04
87 #define BAC_CONTROL_PRIO_HIGH 0x02
88 #define BAC_CONTROL_PRIO_LOW 0x01
90 /* Network Layer Message Types */
91 #define BAC_NET_WHO_R 0x00
92 #define BAC_NET_IAM_R 0x01
93 #define BAC_NET_ICB_R 0x02
94 #define BAC_NET_REJ 0x03
95 #define BAC_NET_R_BUSY 0x04
96 #define BAC_NET_R_AVA 0x05
97 #define BAC_NET_INIT_RTAB 0x06
98 #define BAC_NET_INIT_RTAB_ACK 0x07
99 #define BAC_NET_EST_CON 0x08
100 #define BAC_NET_DISC_CON 0x09
102 static const true_false_string control_net_set_high
= {
103 "network layer message, message type field present.",
104 "BACnet APDU, message type field absent."
107 static const true_false_string control_res_high
= {
108 "Shall be zero, but is one.",
109 "Shall be zero and is zero."
111 static const true_false_string control_dest_high
= {
112 "DNET, DLEN and Hop Count present. If DLEN=0: broadcast, dest. address field absent.",
113 "DNET, DLEN, DADR and Hop Count absent."
116 static const true_false_string control_src_high
= {
117 "SNET, SLEN and SADR present, SLEN=0 invalid, SLEN specifies length of SADR",
118 "SNET, SLEN and SADR absent"
121 static const true_false_string control_expect_high
= {
122 "BACnet-Confirmed-Request-PDU, a segment of BACnet-ComplexACK-PDU or Network Message expecting a reply present.",
123 "Other than a BACnet-Confirmed-Request-PDU, segment of BACnet-ComplexACK-PDU or network layer message expecting a reply present."
126 static const true_false_string control_prio_high_high
= {
127 "Life Safety or Critical Equipment message.",
128 "Not a Life Safety or Critical Equipment message."
131 static const true_false_string control_prio_low_high
= {
137 static int proto_bacnet
= -1;
138 static int hf_bacnet_version
= -1;
139 static int hf_bacnet_control
= -1;
140 static int hf_bacnet_control_net
= -1;
141 static int hf_bacnet_control_res1
= -1;
142 static int hf_bacnet_control_dest
= -1;
143 static int hf_bacnet_control_res2
= -1;
144 static int hf_bacnet_control_src
= -1;
145 static int hf_bacnet_control_expect
= -1;
146 static int hf_bacnet_control_prio_high
= -1;
147 static int hf_bacnet_control_prio_low
= -1;
148 static int hf_bacnet_dnet
= -1;
149 static int hf_bacnet_dlen
= -1;
150 static int hf_bacnet_dadr_eth
= -1;
151 static int hf_bacnet_dadr_mstp
= -1;
152 static int hf_bacnet_dadr_tmp
= -1;
153 static int hf_bacnet_snet
= -1;
154 static int hf_bacnet_slen
= -1;
155 static int hf_bacnet_sadr_eth
= -1;
156 static int hf_bacnet_sadr_mstp
= -1;
157 static int hf_bacnet_sadr_tmp
= -1;
158 static int hf_bacnet_hopc
= -1;
159 static int hf_bacnet_mesgtyp
= -1;
160 static int hf_bacnet_vendor
= -1;
161 static int hf_bacnet_perf
= -1;
162 static int hf_bacnet_rejectreason
= -1;
163 static int hf_bacnet_rportnum
= -1;
164 static int hf_bacnet_portid
= -1;
165 static int hf_bacnet_pinfolen
= -1;
166 static int hf_bacnet_term_time_value
= -1;
168 static gint ett_bacnet
= -1;
169 static gint ett_bacnet_control
= -1;
172 dissect_bacnet(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
176 proto_tree
*bacnet_tree
;
177 proto_tree
*control_tree
;
180 guint8 bacnet_version
;
181 guint8 bacnet_control
;
184 guint8 bacnet_mesgtyp
;
185 guint8 bacnet_rejectreason
;
186 guint8 bacnet_rportnum
;
187 guint8 bacnet_pinfolen
;
192 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BACnet-NPDU");
194 col_set_str(pinfo
->cinfo
, COL_INFO
, "Building Automation and Control Network NPDU");
197 bacnet_version
= tvb_get_guint8(tvb
, offset
);
198 bacnet_control
= tvb_get_guint8(tvb
, offset
+1);
200 /* I don't know the length of the NPDU yet; Setting the length after dissection */
201 ti
= proto_tree_add_item(tree
, proto_bacnet
, tvb
, 0, -1, ENC_NA
);
203 bacnet_tree
= proto_item_add_subtree(ti
, ett_bacnet
);
205 proto_tree_add_uint_format_value(bacnet_tree
, hf_bacnet_version
, tvb
,
207 bacnet_version
,"0x%02x (%s)",bacnet_version
,
208 (bacnet_version
== 0x01)?"ASHRAE 135-1995":"unknown");
210 ct
= proto_tree_add_uint(bacnet_tree
, hf_bacnet_control
,
211 tvb
, offset
, 1, bacnet_control
);
212 control_tree
= proto_item_add_subtree(ct
, ett_bacnet_control
);
213 proto_tree_add_boolean(control_tree
, hf_bacnet_control_net
,
214 tvb
, offset
, 1, bacnet_control
);
215 proto_tree_add_boolean(control_tree
, hf_bacnet_control_res1
, tvb
,
216 offset
, 1, bacnet_control
);
217 proto_tree_add_boolean(control_tree
, hf_bacnet_control_dest
, tvb
,
218 offset
, 1, bacnet_control
);
219 proto_tree_add_boolean(control_tree
, hf_bacnet_control_res2
, tvb
,
220 offset
, 1, bacnet_control
);
221 proto_tree_add_boolean(control_tree
, hf_bacnet_control_src
, tvb
,
222 offset
, 1, bacnet_control
);
223 proto_tree_add_boolean(control_tree
, hf_bacnet_control_expect
, tvb
,
224 offset
, 1, bacnet_control
);
225 proto_tree_add_boolean(control_tree
, hf_bacnet_control_prio_high
,
226 tvb
, offset
, 1, bacnet_control
);
227 proto_tree_add_boolean(control_tree
, hf_bacnet_control_prio_low
,
228 tvb
, offset
, 1, bacnet_control
);
230 if (bacnet_control
& BAC_CONTROL_DEST
) { /* DNET, DLEN, DADR */
231 proto_tree_add_item(bacnet_tree
, hf_bacnet_dnet
,
232 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
234 bacnet_dlen
= tvb_get_guint8(tvb
, offset
);
235 /* DLEN = 0 is broadcast on dest.network */
236 if( bacnet_dlen
== 0) {
237 /* append to hf_bacnet_dlen: broadcast */
238 proto_tree_add_uint_format_value(bacnet_tree
,
239 hf_bacnet_dlen
, tvb
, offset
, 1, bacnet_dlen
,
240 "%d indicates Broadcast on Destination Network",
244 } else if (bacnet_dlen
==6) {
245 proto_tree_add_uint(bacnet_tree
, hf_bacnet_dlen
,
246 tvb
, offset
, 1, bacnet_dlen
);
249 proto_tree_add_item(bacnet_tree
,
250 hf_bacnet_dadr_eth
, tvb
, offset
,
251 bacnet_dlen
, ENC_NA
);
252 offset
+= bacnet_dlen
;
253 } else if (bacnet_dlen
==1) {
254 proto_tree_add_uint(bacnet_tree
, hf_bacnet_dlen
,
255 tvb
, offset
, 1, bacnet_dlen
);
257 /* MS/TP or ARCNET MAC */
258 proto_tree_add_item(bacnet_tree
,
259 hf_bacnet_dadr_mstp
, tvb
, offset
,
260 bacnet_dlen
, ENC_BIG_ENDIAN
);
261 offset
+= bacnet_dlen
;
262 } else if (bacnet_dlen
<7) {
263 proto_tree_add_uint(bacnet_tree
, hf_bacnet_dlen
,
264 tvb
, offset
, 1, bacnet_dlen
);
266 /* Other MAC formats should be included here */
267 proto_tree_add_item(bacnet_tree
,
268 hf_bacnet_dadr_tmp
, tvb
, offset
,
269 bacnet_dlen
, ENC_NA
);
270 offset
+= bacnet_dlen
;
272 proto_tree_add_uint_format_value(bacnet_tree
,
273 hf_bacnet_dlen
, tvb
, offset
, 1, bacnet_dlen
,
278 if (bacnet_control
& BAC_CONTROL_SRC
) { /* SNET, SLEN, SADR */
280 proto_tree_add_uint(bacnet_tree
, hf_bacnet_snet
,
281 tvb
, offset
, 2, tvb_get_ntohs(tvb
, offset
));
283 bacnet_slen
= tvb_get_guint8(tvb
, offset
);
284 if( bacnet_slen
== 0) { /* SLEN = 0 invalid */
285 proto_tree_add_uint_format_value(bacnet_tree
,
286 hf_bacnet_slen
, tvb
, offset
, 1, bacnet_slen
,
290 } else if (bacnet_slen
==6) {
292 proto_tree_add_uint(bacnet_tree
, hf_bacnet_slen
,
293 tvb
, offset
, 1, bacnet_slen
);
296 proto_tree_add_item(bacnet_tree
,
297 hf_bacnet_sadr_eth
, tvb
, offset
,
298 bacnet_slen
, ENC_NA
);
299 offset
+= bacnet_slen
;
300 } else if (bacnet_slen
==1) {
302 proto_tree_add_uint(bacnet_tree
, hf_bacnet_slen
,
303 tvb
, offset
, 1, bacnet_slen
);
305 /* MS/TP or ARCNET MAC */
306 proto_tree_add_item(bacnet_tree
,
307 hf_bacnet_sadr_mstp
, tvb
, offset
,
308 bacnet_slen
, ENC_BIG_ENDIAN
);
309 offset
+= bacnet_slen
;
310 } else if (bacnet_slen
<6) { /* LON MAC */
312 proto_tree_add_uint(bacnet_tree
, hf_bacnet_slen
,
313 tvb
, offset
, 1, bacnet_slen
);
315 /* Other MAC formats should be included here */
316 proto_tree_add_item(bacnet_tree
,
317 hf_bacnet_sadr_tmp
, tvb
, offset
,
318 bacnet_slen
, ENC_NA
);
319 offset
+= bacnet_slen
;
321 proto_tree_add_uint_format_value(bacnet_tree
,
322 hf_bacnet_slen
, tvb
, offset
, 1, bacnet_slen
,
328 if (bacnet_control
& BAC_CONTROL_DEST
) { /* Hopcount */
329 proto_tree_add_item(bacnet_tree
, hf_bacnet_hopc
,
330 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
333 /* Network Layer Message Type */
334 if (bacnet_control
& BAC_CONTROL_NET
) {
335 bacnet_mesgtyp
= tvb_get_guint8(tvb
, offset
);
336 proto_tree_add_uint_format_value(bacnet_tree
,
337 hf_bacnet_mesgtyp
, tvb
, offset
, 1, bacnet_mesgtyp
,
338 "%02x (%s)", bacnet_mesgtyp
,
339 bacnet_mesgtyp_name(bacnet_mesgtyp
));
340 /* Put the NPDU Type in the info column */
341 col_add_str(pinfo
->cinfo
, COL_INFO
,
342 bacnet_mesgtyp_name(bacnet_mesgtyp
));
345 * The standard says: "If Bit 7 of the control octet is 1 and
346 * the Message Type field contains a value in the range
347 * X'80' - X'FF', then a Vendor ID field shall be present (...)."
348 * We should not go any further in dissecting the packet if it's
349 * not present, but we don't know about that: No length field...
351 if (bacnet_mesgtyp
> 0x7f) {
352 /* Note: our next_tvb includes message type and vendor id! */
353 next_tvb
= tvb_new_subset_remaining(tvb
, offset
-1);
354 vendor_id
= tvb_get_ntohs(tvb
, offset
);
355 proto_tree_add_uint(bacnet_tree
, hf_bacnet_vendor
, tvb
,
356 offset
, 2, vendor_id
);
357 offset
+= 2; /* vendor_id */
358 if (dissector_try_uint(bacnet_dissector_table
,
359 vendor_id
, next_tvb
, pinfo
, bacnet_tree
)) {
360 /* we parsed it so skip over length and we are done */
361 /* Note: offset has now been bumped for message type and vendor id so we take that out of our next_tvb size */
362 offset
+= tvb_length(next_tvb
) -3;
365 /* Performance Index (in I-Could-Be-Router-To-Network) */
366 if (bacnet_mesgtyp
== BAC_NET_ICB_R
) {
367 proto_tree_add_item(bacnet_tree
, hf_bacnet_dnet
,
368 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
370 proto_tree_add_item(bacnet_tree
, hf_bacnet_perf
,
371 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
374 /* Reason, DNET (in Reject-Message-To-Network) */
375 if (bacnet_mesgtyp
== BAC_NET_REJ
) {
376 bacnet_rejectreason
= tvb_get_guint8(tvb
, offset
);
377 proto_tree_add_uint_format_value(bacnet_tree
,
378 hf_bacnet_rejectreason
,
380 bacnet_rejectreason
, "%d (%s)",
382 bacnet_rejectreason_name(bacnet_rejectreason
));
384 proto_tree_add_item(bacnet_tree
, hf_bacnet_dnet
,
385 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
388 /* N*DNET (in Router-Busy-To-Network,Router-Available-To-Network) */
389 if ((bacnet_mesgtyp
== BAC_NET_R_BUSY
) ||
390 (bacnet_mesgtyp
== BAC_NET_WHO_R
) ||
391 (bacnet_mesgtyp
== BAC_NET_R_AVA
) ||
392 (bacnet_mesgtyp
== BAC_NET_IAM_R
) ) {
393 while(tvb_reported_length_remaining(tvb
, offset
) > 1 ) {
394 proto_tree_add_item(bacnet_tree
, hf_bacnet_dnet
,
395 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
399 /* Initialize-Routing-Table */
400 if ( (bacnet_mesgtyp
== BAC_NET_INIT_RTAB
) ||
401 (bacnet_mesgtyp
== BAC_NET_INIT_RTAB_ACK
) ) {
402 bacnet_rportnum
= tvb_get_guint8(tvb
, offset
);
403 /* number of ports */
404 proto_tree_add_uint(bacnet_tree
, hf_bacnet_rportnum
,
405 tvb
, offset
, 1, bacnet_rportnum
);
407 for(i
=0; i
<bacnet_rportnum
; i
++) {
409 proto_tree_add_item(bacnet_tree
, hf_bacnet_dnet
,
410 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
413 proto_tree_add_item(bacnet_tree
, hf_bacnet_portid
,
414 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
416 /* Port Info Length */
417 bacnet_pinfolen
= tvb_get_guint8(tvb
, offset
);
418 proto_tree_add_uint(bacnet_tree
, hf_bacnet_pinfolen
,
419 tvb
, offset
, 1, bacnet_pinfolen
);
421 proto_tree_add_text(bacnet_tree
, tvb
, offset
,
422 bacnet_pinfolen
, "Port Info: %s",
423 tvb_bytes_to_str(tvb
, offset
, bacnet_pinfolen
));
424 offset
+= bacnet_pinfolen
;
427 /* Establish-Connection-To-Network */
428 if (bacnet_mesgtyp
== BAC_NET_EST_CON
) {
429 proto_tree_add_item(bacnet_tree
, hf_bacnet_dnet
,
430 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
432 proto_tree_add_item(bacnet_tree
, hf_bacnet_term_time_value
,
433 tvb
, offset
, 1, ENC_BIG_ENDIAN
);
436 /* Disconnect-Connection-To-Network */
437 if (bacnet_mesgtyp
== BAC_NET_DISC_CON
) {
438 proto_tree_add_item(bacnet_tree
, hf_bacnet_dnet
,
439 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
443 /* Now set NPDU length */
444 proto_item_set_len(ti
, offset
);
446 /* dissect BACnet APDU */
447 next_tvb
= tvb_new_subset_remaining(tvb
,offset
);
448 if (bacnet_control
& BAC_CONTROL_NET
) {
449 /* Unknown function - dissect the payload as data */
450 call_dissector(data_handle
, next_tvb
, pinfo
, tree
);
452 /* APDU - call the APDU dissector */
453 call_dissector(bacapp_handle
, next_tvb
, pinfo
, tree
);
458 proto_register_bacnet(void)
460 static hf_register_info hf
[] = {
461 { &hf_bacnet_version
,
462 { "Version", "bacnet.version",
463 FT_UINT8
, BASE_DEC
, NULL
, 0,
464 "BACnet Version", HFILL
}
466 { &hf_bacnet_control
,
467 { "Control", "bacnet.control",
468 FT_UINT8
, BASE_HEX
, NULL
, 0,
469 "BACnet Control", HFILL
}
471 { &hf_bacnet_control_net
,
473 "bacnet.control_net",
474 FT_BOOLEAN
, 8, TFS(&control_net_set_high
),
475 BAC_CONTROL_NET
, "BACnet Control", HFILL
}
477 { &hf_bacnet_control_res1
,
479 "bacnet.control_res1",
480 FT_BOOLEAN
, 8, TFS(&control_res_high
),
481 BAC_CONTROL_RES1
, "BACnet Control", HFILL
}
483 { &hf_bacnet_control_dest
,
484 { "Destination Specifier",
485 "bacnet.control_dest",
486 FT_BOOLEAN
, 8, TFS(&control_dest_high
),
487 BAC_CONTROL_DEST
, "BACnet Control", HFILL
}
489 { &hf_bacnet_control_res2
,
491 "bacnet.control_res2",
492 FT_BOOLEAN
, 8, TFS(&control_res_high
),
493 BAC_CONTROL_RES2
, "BACnet Control", HFILL
}
495 { &hf_bacnet_control_src
,
496 { "Source specifier",
497 "bacnet.control_src",
498 FT_BOOLEAN
, 8, TFS(&control_src_high
),
499 BAC_CONTROL_SRC
, "BACnet Control", HFILL
}
501 { &hf_bacnet_control_expect
,
503 "bacnet.control_expect",
504 FT_BOOLEAN
, 8, TFS(&control_expect_high
),
505 BAC_CONTROL_EXPECT
, "BACnet Control", HFILL
}
507 { &hf_bacnet_control_prio_high
,
509 "bacnet.control_prio_high",
510 FT_BOOLEAN
, 8, TFS(&control_prio_high_high
),
511 BAC_CONTROL_PRIO_HIGH
, "BACnet Control", HFILL
}
513 { &hf_bacnet_control_prio_low
,
515 "bacnet.control_prio_low",
516 FT_BOOLEAN
, 8, TFS(&control_prio_low_high
),
517 BAC_CONTROL_PRIO_LOW
, "BACnet Control", HFILL
}
520 { "Destination Network Address", "bacnet.dnet",
521 FT_UINT16
, BASE_DEC
, NULL
, 0,
525 { "Destination MAC Layer Address Length", "bacnet.dlen",
526 FT_UINT8
, BASE_DEC
, NULL
, 0,
529 { &hf_bacnet_dadr_eth
,
530 { "Destination ISO 8802-3 MAC Address", "bacnet.dadr_eth",
531 FT_ETHER
, BASE_NONE
, NULL
, 0,
534 { &hf_bacnet_dadr_mstp
,
535 { "DADR", "bacnet.dadr_mstp",
536 FT_UINT8
, BASE_DEC
, NULL
, 0,
537 "Destination MS/TP or ARCNET MAC Address", HFILL
}
539 { &hf_bacnet_dadr_tmp
,
540 { "Unknown Destination MAC", "bacnet.dadr_tmp",
541 FT_BYTES
, BASE_NONE
, NULL
, 0,
545 { "Source Network Address", "bacnet.snet",
546 FT_UINT16
, BASE_DEC
, NULL
, 0,
550 { "Source MAC Layer Address Length", "bacnet.slen",
551 FT_UINT8
, BASE_DEC
, NULL
, 0,
554 { &hf_bacnet_sadr_eth
,
555 { "SADR", "bacnet.sadr_eth",
556 FT_ETHER
, BASE_NONE
, NULL
, 0,
557 "Source ISO 8802-3 MAC Address", HFILL
}
559 { &hf_bacnet_sadr_mstp
,
560 { "SADR", "bacnet.sadr_mstp",
561 FT_UINT8
, BASE_DEC
, NULL
, 0,
562 "Source MS/TP or ARCNET MAC Address", HFILL
}
564 { &hf_bacnet_sadr_tmp
,
565 { "Unknown Source MAC", "bacnet.sadr_tmp",
566 FT_BYTES
, BASE_NONE
, NULL
, 0,
570 { "Hop Count", "bacnet.hopc",
571 FT_UINT8
, BASE_DEC
, NULL
, 0,
574 { &hf_bacnet_mesgtyp
,
575 { "Network Layer Message Type", "bacnet.mesgtyp",
576 FT_UINT8
, BASE_HEX
, NULL
, 0,
580 { "Vendor ID", "bacnet.vendor",
581 FT_UINT16
, BASE_DEC
, NULL
, 0,
585 { "Performance Index", "bacnet.perf",
586 FT_UINT8
, BASE_DEC
, NULL
, 0,
589 { &hf_bacnet_rejectreason
,
590 { "Reject Reason", "bacnet.rejectreason",
591 FT_UINT8
, BASE_DEC
, NULL
, 0,
594 { &hf_bacnet_rportnum
,
595 { "Number of Port Mappings", "bacnet.rportnum",
596 FT_UINT8
, BASE_DEC
, NULL
, 0,
599 { &hf_bacnet_pinfolen
,
600 { "Port Info Length", "bacnet.pinfolen",
601 FT_UINT8
, BASE_DEC
, NULL
, 0,
605 { "Port ID", "bacnet.portid",
606 FT_UINT8
, BASE_HEX
, NULL
, 0,
609 { &hf_bacnet_term_time_value
,
610 { "Termination Time Value (seconds)", "bacnet.term_time_value",
611 FT_UINT8
, BASE_DEC
, NULL
, 0,
612 "Termination Time Value", HFILL
}
616 static gint
*ett
[] = {
621 proto_bacnet
= proto_register_protocol("Building Automation and Control Network NPDU",
624 proto_register_field_array(proto_bacnet
, hf
, array_length(hf
));
625 proto_register_subtree_array(ett
, array_length(ett
));
627 register_dissector("bacnet", dissect_bacnet
, proto_bacnet
);
629 bacnet_dissector_table
= register_dissector_table("bacnet.vendor",
630 "BACnet Vendor Identifier",
635 proto_reg_handoff_bacnet(void)
637 dissector_handle_t bacnet_handle
;
639 bacnet_handle
= find_dissector("bacnet");
640 dissector_add_uint("bvlc.function", 0x04, bacnet_handle
);
641 dissector_add_uint("bvlc.function", 0x09, bacnet_handle
);
642 dissector_add_uint("bvlc.function", 0x0a, bacnet_handle
);
643 dissector_add_uint("bvlc.function", 0x0b, bacnet_handle
);
644 dissector_add_uint("llc.dsap", SAP_BACNET
, bacnet_handle
);
645 bacapp_handle
= find_dissector("bacapp");
646 data_handle
= find_dissector("data");