Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-mstp.c
blobc6eb39172d58d73614fdbd051e2801984b9d8000
1 /* packet-mstp.c
2 * Routines for BACnet MS/TP datalink dissection
3 * Copyright 2008 Steve Karg <skarg@users.sourceforge.net> Alabama
5 * This is described in Clause 9 of ANSI/ASHRAE Standard 135-2004,
6 * BACnet - A Data Communication Protocol for Building Automation
7 * and Contrl Networks; clause 9 "describes a Master-Slave/Token-Passing
8 * (MS/TP) data link protocol, which provides the same services to the
9 * network layer as ISO 8802-2 Logical Link Control. It uses services
10 * provided by the EIA-485 physical layer." See section 9.3 for the
11 * frame format.
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
17 * SPDX-License-Identifier: GPL-2.0-or-later
20 #include "config.h"
22 #include <epan/packet.h>
23 #include <wiretap/wtap.h>
24 #include <epan/expert.h>
25 #include <epan/address_types.h>
26 #include <epan/to_str.h>
27 #include "packet-mstp.h"
29 void proto_register_mstp(void);
30 void proto_reg_handoff_mstp(void);
32 /* Probably should be a preference, but here for now */
33 #define BACNET_MSTP_SUMMARY_IN_TREE
34 #define BACNET_MSTP_CHECKSUM_VALIDATE
36 /* MS/TP Frame Type */
37 /* Frame Types 8 through 127 are reserved by ASHRAE. */
38 #define MSTP_TOKEN 0x00
39 #define MSTP_POLL_FOR_MASTER 0x01
40 #define MSTP_REPLY_TO_POLL_FOR_MASTER 0x02
41 #define MSTP_TEST_REQUEST 0x03
42 #define MSTP_TEST_RESPONSE 0x04
43 #define MSTP_BACNET_DATA_EXPECTING_REPLY 0x05
44 #define MSTP_BACNET_DATA_NOT_EXPECTING_REPLY 0x06
45 #define MSTP_REPLY_POSTPONED 0x07
46 #define MSTP_BACNET_EXTENDED_DATA_EXPECTING_REPLY 0x20
47 #define MSTP_BACNET_EXTENDED_DATA_NOT_EXPECTING_REPLY 0x21
50 static const value_string
51 bacnet_mstp_frame_type_name[] = {
52 {MSTP_TOKEN, "Token"},
53 {MSTP_POLL_FOR_MASTER, "Poll For Master"},
54 {MSTP_REPLY_TO_POLL_FOR_MASTER, "Reply To Poll For Master"},
55 {MSTP_TEST_REQUEST, "Test_Request"},
56 {MSTP_TEST_RESPONSE, "Test_Response"},
57 {MSTP_BACNET_DATA_EXPECTING_REPLY, "BACnet Data Expecting Reply"},
58 {MSTP_BACNET_DATA_NOT_EXPECTING_REPLY, "BACnet Data Not Expecting Reply"},
59 {MSTP_REPLY_POSTPONED, "Reply Postponed"},
60 {MSTP_BACNET_EXTENDED_DATA_EXPECTING_REPLY, "BACnet Extended Data Expecting Reply"},
61 {MSTP_BACNET_EXTENDED_DATA_NOT_EXPECTING_REPLY, "BACnet Extended Data Not Expecting Reply"},
62 /* Frame Types 128 through 255: Proprietary Frames */
63 {0, NULL }
66 static dissector_table_t subdissector_table;
68 static int proto_mstp;
70 static int ett_bacnet_mstp;
71 static int ett_bacnet_mstp_checksum;
73 static int hf_mstp_preamble_55;
74 static int hf_mstp_preamble_FF;
75 static int hf_mstp_frame_type;
76 static int hf_mstp_frame_destination;
77 static int hf_mstp_frame_source;
78 static int hf_mstp_frame_vendor_id;
79 static int hf_mstp_frame_pdu_len;
80 static int hf_mstp_frame_crc8;
81 static int hf_mstp_frame_crc16;
82 static int hf_mstp_frame_checksum_status;
84 static expert_field ei_mstp_frame_pdu_len;
85 static expert_field ei_mstp_frame_checksum_bad;
87 static int mstp_address_type = -1;
89 static dissector_handle_t mstp_handle;
91 #if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
92 /* Accumulate "dataValue" into the CRC in crcValue. */
93 /* Return value is updated CRC */
94 /* The ^ operator means exclusive OR. */
95 /* Note: This function is copied directly from the BACnet standard. */
96 static uint8_t
97 CRC_Calc_Header(
98 uint8_t dataValue,
99 uint8_t crcValue)
101 uint16_t crc;
103 crc = crcValue ^ dataValue; /* XOR C7..C0 with D7..D0 */
105 /* Exclusive OR the terms in the table (top down) */
106 crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3)
107 ^ (crc << 4) ^ (crc << 5) ^ (crc << 6)
108 ^ (crc << 7);
110 /* Combine bits shifted out left hand end */
111 return (crc & 0xfe) ^ ((crc >> 8) & 1);
113 #endif
115 #if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
116 /* Accumulate "dataValue" into the CRC in crcValue. */
117 /* Return value is updated CRC */
118 /* The ^ operator means exclusive OR. */
119 /* Note: This function is copied directly from the BACnet standard. */
120 static uint16_t
121 CRC_Calc_Data(
122 uint8_t dataValue,
123 uint16_t crcValue)
125 uint16_t crcLow;
127 crcLow = (crcValue & 0xff) ^ dataValue; /* XOR C7..C0 with D7..D0 */
129 /* Exclusive OR the terms in the table (top down) */
130 return (crcValue >> 8) ^ (crcLow << 8) ^ (crcLow << 3)
131 ^ (crcLow << 12) ^ (crcLow >> 4)
132 ^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
134 #endif
136 /* Common frame type text */
137 const char *
138 mstp_frame_type_text(uint32_t val)
140 return val_to_str(val,
141 bacnet_mstp_frame_type_name,
142 "Unknown Frame Type (%u)");
145 static int mstp_str_len(const address* addr _U_)
147 return 5;
150 static int mstp_to_str(const address* addr, char *buf, int buf_len _U_)
152 *buf++ = '0';
153 *buf++ = 'x';
154 buf = bytes_to_hexstr(buf, (const uint8_t *)addr->data, 1);
155 *buf = '\0'; /* NULL terminate */
157 return mstp_str_len(addr);
160 static const char* mstp_col_filter_str(const address* addr _U_, bool is_src)
162 if (is_src)
163 return "mstp.src";
165 return "mstp.dst";
168 static int mstp_len(void)
170 return 1;
173 static uint32_t calc_data_crc32(uint8_t dataValue, uint32_t crc32kValue)
175 uint8_t data;
176 uint8_t b;
177 uint32_t crc;
179 data = dataValue;
180 crc = crc32kValue;
182 for (b = 0; b < 8; b++)
184 if ((data & 1) ^ (crc & 1))
186 crc >>= 1;
187 crc ^= 0xEB31D82E;
189 else
191 crc >>= 1;
194 data >>= 1;
197 return crc;
201 * Decodes 'length' octets of data located at 'from' and
202 * writes the original client data at 'to', restoring any
203 * 'mask' octets that may present in the encoded data.
204 * Returns the length of the encoded data or zero if error.
205 * The length of the encoded value is always smaller or equal to 'length'.
207 static size_t cobs_decode(uint8_t *to, const uint8_t *from, size_t length, uint8_t mask)
209 size_t read_index = 0;
210 size_t write_index = 0;
211 uint8_t code;
212 uint8_t last_code;
214 while (read_index < length)
216 code = from[read_index] ^ mask;
217 last_code = code;
219 * A code octet equal to zero or greater than the length is illegal.
221 if (code == 0 || read_index + code > length)
222 return 0;
224 read_index++;
226 * Decode data octets. The code octet is included in the length, but the
227 * terminating zero octet is not. (Note that a data octet of zero should not
228 * occur here since the whole point of COBS encoding is to remove zeroes.)
230 while (--code > 0)
231 to[write_index++] = from[read_index++] ^ mask;
234 * Restore the implicit zero at the end of each decoded block
235 * except when it contains exactly 254 non-zero octets or the
236 * end of data has been reached.
238 if ((last_code != 255) && (read_index < length))
239 to[write_index++] = 0;
242 return write_index;
245 #define SIZEOF_ENC_CRC 5
246 #define CRC32K_INITIAL_VALUE 0xFFFFFFFF
247 #define CRC32K_RESIDUE 0x0843323B
248 #define MSTP_PREAMBLE_X55 0x55
251 * Decodes Encoded Data and Encoded CRC-32K fields at 'from' (of length 'length')
252 * and writes the decoded client data at 'to'.
253 * Returns length of decoded Data in octets or zero if error.
254 * NOTE: Safe to call with 'output' <= 'input' (decodes in place).
256 static size_t cobs_frame_decode(uint8_t *to, const uint8_t *from, size_t length)
258 size_t data_len;
259 size_t crc_len;
260 uint32_t crc32K;
261 uint32_t i;
263 /* Must have enough room for the encoded CRC-32K value. */
264 if (length < SIZEOF_ENC_CRC)
265 return 0;
268 * Calculate the CRC32K over the Encoded Data octets before decoding.
269 * NOTE: Adjust 'length' by removing size of Encoded CRC-32K field.
271 data_len = length - SIZEOF_ENC_CRC;
272 crc32K = CRC32K_INITIAL_VALUE;
273 for (i = 0; i < data_len; i++)
274 crc32K = calc_data_crc32(from[i], crc32K);
276 data_len = cobs_decode(to, from, data_len, MSTP_PREAMBLE_X55);
278 * Decode the Encoded CRC-32K field and append to data.
280 crc_len = cobs_decode((uint8_t *)(to + data_len),
281 (uint8_t *)(from + length - SIZEOF_ENC_CRC),
282 SIZEOF_ENC_CRC, MSTP_PREAMBLE_X55);
285 * Sanity check length of decoded CRC32K.
287 if (crc_len != sizeof(uint32_t))
288 return 0;
291 * Verify CRC32K of incoming frame.
293 for (i = 0; i < crc_len; i++)
294 crc32K = calc_data_crc32((to + data_len)[i], crc32K);
296 if (crc32K == CRC32K_RESIDUE)
297 return data_len;
299 return 0;
302 /* dissects a BACnet MS/TP frame */
303 /* preamble 0x55 0xFF is not included in Cimetrics U+4 output */
304 void
305 dissect_mstp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
306 proto_tree *subtree, int offset)
308 uint8_t mstp_frame_type = 0;
309 uint16_t mstp_frame_pdu_len = 0;
310 uint16_t mstp_tvb_pdu_len = 0;
311 uint16_t vendorid = 0;
312 tvbuff_t *next_tvb = NULL;
313 proto_item *item;
314 #if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
315 /* used to calculate the crc value */
316 uint8_t crc8 = 0xFF;
317 uint16_t crc16 = 0xFFFF;
318 uint8_t crcdata;
319 uint16_t i; /* loop counter */
320 uint16_t max_len = 0;
321 #endif
323 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BACnet");
324 col_set_str(pinfo->cinfo, COL_INFO, "BACnet MS/TP");
325 mstp_frame_type = tvb_get_uint8(tvb, offset);
326 mstp_frame_pdu_len = tvb_get_ntohs(tvb, offset+3);
327 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
328 mstp_frame_type_text(mstp_frame_type));
330 /* Add the items to the tree */
331 proto_tree_add_item(subtree, hf_mstp_frame_type, tvb,
332 offset, 1, ENC_LITTLE_ENDIAN);
333 proto_tree_add_item(subtree, hf_mstp_frame_destination, tvb,
334 offset+1, 1, ENC_LITTLE_ENDIAN);
335 proto_tree_add_item(subtree, hf_mstp_frame_source, tvb,
336 offset+2, 1, ENC_LITTLE_ENDIAN);
337 item = proto_tree_add_item(subtree, hf_mstp_frame_pdu_len, tvb,
338 offset+3, 2, ENC_BIG_ENDIAN);
339 mstp_tvb_pdu_len = tvb_reported_length_remaining(tvb, offset+6);
340 /* check the length - which does not include the crc16 checksum */
341 if (mstp_tvb_pdu_len > 2) {
342 if (mstp_frame_pdu_len > (mstp_tvb_pdu_len-2)) {
343 expert_add_info(pinfo, item, &ei_mstp_frame_pdu_len);
346 #if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
347 /* calculate checksum to validate */
348 for (i = 0; i < 5; i++) {
349 crcdata = tvb_get_uint8(tvb, offset+i);
350 crc8 = CRC_Calc_Header(crcdata, crc8);
352 crc8 = ~crc8;
353 proto_tree_add_checksum(subtree, tvb, offset+5, hf_mstp_frame_crc8, hf_mstp_frame_checksum_status, &ei_mstp_frame_checksum_bad, pinfo, crc8,
354 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
355 #else
356 proto_tree_add_checksum(subtree, tvb, offset+5, hf_mstp_frame_crc8, hf_mstp_frame_checksum_status, &ei_mstp_frame_checksum_bad, pinfo, 0,
357 PROTO_CHECKSUM_NO_FLAGS);
358 #endif
360 /* dissect BACnet PDU if there is one */
361 offset += 6;
363 if (mstp_frame_type == MSTP_BACNET_EXTENDED_DATA_EXPECTING_REPLY ||
364 mstp_frame_type == MSTP_BACNET_EXTENDED_DATA_NOT_EXPECTING_REPLY) {
365 /* handle extended frame types differently because their data need to
366 be 'decoded' first */
367 uint8_t *decode_base;
368 tvbuff_t *decoded_tvb;
369 uint16_t decoded_len = mstp_frame_pdu_len;
371 decode_base = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, mstp_frame_pdu_len + 2);
372 decoded_len = (uint16_t)cobs_frame_decode(decode_base, decode_base, decoded_len + 2);
373 if (decoded_len > 0) {
374 decoded_tvb = tvb_new_real_data(decode_base, decoded_len, decoded_len);
375 tvb_set_child_real_data_tvbuff(tvb, decoded_tvb);
376 add_new_data_source(pinfo, decoded_tvb, "Decoded Data");
378 if (!(dissector_try_uint(subdissector_table, (vendorid << 16) + mstp_frame_type,
379 decoded_tvb, pinfo, tree))) {
380 /* Unknown function - dissect the payload as data */
381 call_data_dissector(decoded_tvb, pinfo, tree);
384 proto_tree_add_checksum(subtree, tvb, offset + mstp_frame_pdu_len, hf_mstp_frame_crc16, hf_mstp_frame_checksum_status, &ei_mstp_frame_checksum_bad,
385 pinfo, tvb_get_ntohs(tvb, offset + mstp_frame_pdu_len), ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
386 } else {
387 next_tvb = tvb_new_subset_length(tvb, offset,
388 mstp_tvb_pdu_len);
389 call_data_dissector(next_tvb, pinfo, tree);
390 proto_tree_add_checksum(subtree, tvb, offset + mstp_frame_pdu_len, hf_mstp_frame_crc16, hf_mstp_frame_checksum_status, &ei_mstp_frame_checksum_bad, pinfo, 0,
391 ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
394 else if (mstp_tvb_pdu_len > 2) {
395 /* remove the 16-bit crc checksum bytes */
396 mstp_tvb_pdu_len -= 2;
397 if (mstp_frame_type < 128) {
398 vendorid = 0;
399 next_tvb = tvb_new_subset_length(tvb, offset,
400 mstp_tvb_pdu_len);
401 } else {
402 /* With Vendor ID */
403 vendorid = tvb_get_ntohs(tvb, offset);
405 /* Write Vendor ID as tree */
406 proto_tree_add_item(subtree, hf_mstp_frame_vendor_id, tvb,
407 offset, 2, ENC_BIG_ENDIAN);
409 /* NPDU - call the Vendor specific dissector */
410 next_tvb = tvb_new_subset_length_caplen(tvb, offset+2,
411 mstp_tvb_pdu_len-2, mstp_frame_pdu_len);
414 if (!(dissector_try_uint(subdissector_table, (vendorid<<16) + mstp_frame_type,
415 next_tvb, pinfo, tree))) {
416 /* Unknown function - dissect the payload as data */
417 call_data_dissector(next_tvb, pinfo, tree);
419 #if defined(BACNET_MSTP_CHECKSUM_VALIDATE)
420 /* 16-bit checksum - calculate to validate */
421 max_len = MIN(mstp_frame_pdu_len, mstp_tvb_pdu_len);
422 for (i = 0; i < max_len; i++) {
423 crcdata = tvb_get_uint8(tvb, offset+i);
424 crc16 = CRC_Calc_Data(crcdata, crc16);
426 crc16 = ~crc16;
427 /* convert it to on-the-wire format */
428 crc16 = g_htons(crc16);
430 proto_tree_add_checksum(subtree, tvb, offset+mstp_frame_pdu_len, hf_mstp_frame_crc16, hf_mstp_frame_checksum_status, &ei_mstp_frame_checksum_bad, pinfo, crc16,
431 ENC_BIG_ENDIAN, PROTO_CHECKSUM_VERIFY);
432 #else
433 proto_tree_add_checksum(subtree, tvb, offset+mstp_frame_pdu_len, hf_mstp_frame_crc16, hf_mstp_frame_checksum_status, &ei_mstp_frame_checksum_bad, pinfo, 0,
434 ENC_BIG_ENDIAN, PROTO_CHECKSUM_NO_FLAGS);
435 #endif
439 static int
440 dissect_mstp_wtap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
442 proto_item *ti;
443 proto_tree *subtree;
444 int offset = 0;
445 #ifdef BACNET_MSTP_SUMMARY_IN_TREE
446 uint8_t mstp_frame_type = 0;
447 uint8_t mstp_frame_source = 0;
448 uint8_t mstp_frame_destination = 0;
449 #endif
451 /* set the MS/TP MAC address in the source/destination */
452 set_address_tvb(&pinfo->dl_dst, mstp_address_type, 1, tvb, offset+3);
453 copy_address_shallow(&pinfo->dst, &pinfo->dl_dst);
454 set_address_tvb(&pinfo->dl_src, mstp_address_type, 1, tvb, offset+4);
455 copy_address_shallow(&pinfo->src, &pinfo->dl_src);
457 #ifdef BACNET_MSTP_SUMMARY_IN_TREE
458 mstp_frame_type = tvb_get_uint8(tvb, offset+2);
459 mstp_frame_destination = tvb_get_uint8(tvb, offset+3);
460 mstp_frame_source = tvb_get_uint8(tvb, offset+4);
461 ti = proto_tree_add_protocol_format(tree, proto_mstp, tvb, offset, 8,
462 "BACnet MS/TP, Src (%u), Dst (%u), %s",
463 mstp_frame_source, mstp_frame_destination,
464 mstp_frame_type_text(mstp_frame_type));
465 #else
466 ti = proto_tree_add_item(tree, proto_mstp, tvb, offset, 8, ENC_NA);
467 #endif
468 subtree = proto_item_add_subtree(ti, ett_bacnet_mstp);
469 proto_tree_add_item(subtree, hf_mstp_preamble_55, tvb,
470 offset, 1, ENC_LITTLE_ENDIAN);
471 proto_tree_add_item(subtree, hf_mstp_preamble_FF, tvb,
472 offset+1, 1, ENC_LITTLE_ENDIAN);
473 dissect_mstp(tvb, pinfo, tree, subtree, offset+2);
474 return tvb_captured_length(tvb);
477 void
478 proto_register_mstp(void)
480 static hf_register_info hf[] = {
481 { &hf_mstp_preamble_55,
482 { "Preamble 55", "mstp.preamble_55",
483 FT_UINT8, BASE_HEX, NULL, 0,
484 "MS/TP Preamble 55", HFILL }
486 { &hf_mstp_preamble_FF,
487 { "Preamble FF", "mstp.preamble_FF",
488 FT_UINT8, BASE_HEX, NULL, 0,
489 "MS/TP Preamble FF", HFILL }
491 { &hf_mstp_frame_type,
492 { "Frame Type", "mstp.frame_type",
493 FT_UINT8, BASE_DEC, VALS(bacnet_mstp_frame_type_name), 0,
494 "MS/TP Frame Type", HFILL }
496 { &hf_mstp_frame_destination,
497 { "Destination Address", "mstp.dst",
498 FT_UINT8, BASE_DEC, NULL, 0,
499 "Destination MS/TP MAC Address", HFILL }
501 { &hf_mstp_frame_source,
502 { "Source Address", "mstp.src",
503 FT_UINT8, BASE_DEC, NULL, 0,
504 "Source MS/TP MAC Address", HFILL }
506 { &hf_mstp_frame_vendor_id,
507 { "VendorID", "mstp.vendorid",
508 FT_UINT16, BASE_DEC, NULL, 0,
509 "MS/TP Vendor ID of proprietary frametypes", HFILL }
511 { &hf_mstp_frame_pdu_len,
512 { "Length", "mstp.len",
513 FT_UINT16, BASE_DEC, NULL, 0,
514 "MS/TP Data Length", HFILL }
516 { &hf_mstp_frame_crc8,
517 { "Header CRC", "mstp.hdr_crc",
518 FT_UINT8, BASE_HEX, NULL, 0,
519 "MS/TP Header CRC", HFILL }
521 { &hf_mstp_frame_crc16,
522 { "Data CRC", "mstp.data_crc",
523 FT_UINT16, BASE_HEX, NULL, 0,
524 "MS/TP Data CRC", HFILL }
526 { &hf_mstp_frame_checksum_status,
527 { "Checksum status", "mstp.checksum.status",
528 FT_UINT8, BASE_NONE, VALS(proto_checksum_vals), 0x0,
529 NULL, HFILL }
533 static int *ett[] = {
534 &ett_bacnet_mstp,
535 &ett_bacnet_mstp_checksum
538 static ei_register_info ei[] = {
539 { &ei_mstp_frame_pdu_len, { "mstp.len.bad", PI_MALFORMED, PI_ERROR, "Length field value goes past the end of the payload", EXPFILL }},
540 { &ei_mstp_frame_checksum_bad, { "mstp.checksum_bad.expert", PI_CHECKSUM, PI_WARN, "Bad Checksum", EXPFILL }},
543 expert_module_t* expert_mstp;
545 proto_mstp = proto_register_protocol("BACnet MS/TP", "BACnet MS/TP", "mstp");
547 proto_register_field_array(proto_mstp, hf, array_length(hf));
548 proto_register_subtree_array(ett, array_length(ett));
549 expert_mstp = expert_register_protocol(proto_mstp);
550 expert_register_field_array(expert_mstp, ei, array_length(ei));
552 mstp_handle = register_dissector("mstp", dissect_mstp_wtap, proto_mstp);
554 subdissector_table = register_dissector_table("mstp.vendor_frame_type",
555 "MSTP Vendor specific Frametypes", proto_mstp, FT_UINT24, BASE_DEC);
556 /* Table_type: (Vendor ID << 16) + Frametype */
558 mstp_address_type = address_type_dissector_register("AT_MSTP", "BACnet MS/TP Address", mstp_to_str, mstp_str_len, NULL, mstp_col_filter_str, mstp_len, NULL, NULL);
561 void
562 proto_reg_handoff_mstp(void)
564 dissector_handle_t bacnet_handle;
566 dissector_add_uint("wtap_encap", WTAP_ENCAP_BACNET_MS_TP, mstp_handle);
567 dissector_add_uint("wtap_encap", WTAP_ENCAP_BACNET_MS_TP_WITH_PHDR, mstp_handle);
569 bacnet_handle = find_dissector("bacnet");
571 dissector_add_uint("mstp.vendor_frame_type", (0/*VendorID ASHRAE*/ << 16) + MSTP_BACNET_DATA_EXPECTING_REPLY, bacnet_handle);
572 dissector_add_uint("mstp.vendor_frame_type", (0/*VendorID ASHRAE*/ << 16) + MSTP_BACNET_DATA_NOT_EXPECTING_REPLY, bacnet_handle);
573 dissector_add_uint("mstp.vendor_frame_type", (0/*VendorID ASHRAE*/ << 16) + MSTP_BACNET_EXTENDED_DATA_EXPECTING_REPLY, bacnet_handle);
574 dissector_add_uint("mstp.vendor_frame_type", (0/*VendorID ASHRAE*/ << 16) + MSTP_BACNET_EXTENDED_DATA_NOT_EXPECTING_REPLY, bacnet_handle);
578 * Editor modelines - https://www.wireshark.org/tools/modelines.html
580 * Local variables:
581 * c-basic-offset: 8
582 * tab-width: 8
583 * indent-tabs-mode: t
584 * End:
586 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
587 * :indentSize=8:tabSize=8:noTabs=false: