Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-bvlc.c
Line
Count
Source
1
/* packet-bvlc.c
2
 * Routines for BACnet/IP (BVLL, BVLC) dissection
3
 * Copyright 2001, Hartmut Mueller <hartmut@abmlinux.org>, FH Dortmund
4
 *
5
 * Wireshark - Network traffic analyzer
6
 * By Gerald Combs <gerald@wireshark.org>
7
 * Copyright 1998 Gerald Combs
8
 *
9
 * Copied from README.developer,v 1.23
10
 *
11
 * SPDX-License-Identifier: GPL-2.0-or-later
12
 */
13
14
#include "config.h"
15
16
#include <epan/packet.h>
17
#include <epan/tfs.h>
18
19
#include "packet-bacnet.h"
20
#include "packet-bacapp.h"
21
22
void proto_register_bvlc(void);
23
void proto_reg_handoff_bvlc(void);
24
25
15
#define BVLC_UDP_PORT 0xBAC0
26
27
/* Network Layer Wrapper Control Information */
28
#define BAC_WRAPPER_CONTROL_NET   0x80
29
#define BAC_WRAPPER_MSG_ENCRYPED  0x40
30
#define BAC_WRAPPER_RESERVED    0x20
31
#define BAC_WRAPPER_AUTHD_PRESENT 0x10
32
#define BAC_WRAPPER_DO_NOT_UNWRAP 0x08
33
#define BAC_WRAPPER_DO_NOT_DECRPT 0x04
34
#define BAC_WRAPPER_NO_TRUST_SRC  0x02
35
#define BAC_WRAPPER_SECURE_BY_RTR 0x01
36
37
static int proto_bvlc;
38
static int proto_bscvlc;
39
static int hf_bvlc_type;
40
static int hf_bvlc_function;
41
static int hf_bvlc_ipv6_function;
42
static int hf_bvlc_length;
43
static int hf_bvlc_result_ip4;
44
static int hf_bvlc_result_ip6;
45
static int hf_bvlc_bdt_ip;
46
static int hf_bvlc_bdt_mask;
47
static int hf_bvlc_bdt_port;
48
static int hf_bvlc_reg_ttl;
49
static int hf_bvlc_fdt_ip;
50
static int hf_bvlc_fdt_ipv6;
51
static int hf_bvlc_fdt_port;
52
static int hf_bvlc_fdt_ttl;
53
static int hf_bvlc_fdt_timeout;
54
static int hf_bvlc_fwd_ip;
55
static int hf_bvlc_fwd_port;
56
static int hf_bvlc_virt_source;
57
static int hf_bvlc_virt_dest;
58
static int hf_bvlc_orig_source_addr;
59
static int hf_bvlc_orig_source_port;
60
static int hf_bscvlc_control;
61
static int hf_bscvlc_control_data_option;
62
static int hf_bscvlc_control_destination_option;
63
static int hf_bscvlc_control_destination_address;
64
static int hf_bscvlc_control_origin_address;
65
static int hf_bscvlc_control_reserved;
66
static int hf_bscvlc_header;
67
static int hf_bscvlc_header_marker;
68
static int hf_bscvlc_header_length;
69
static int hf_bscvlc_header_data;
70
static int hf_bscvlc_header_opt_type;
71
static int hf_bscvlc_header_opt_data;
72
static int hf_bscvlc_header_opt_must_understand;
73
static int hf_bscvlc_header_opt_more;
74
static int hf_bscvlc_vendor_id;
75
static int hf_bscvlc_proprietary_opt_type;
76
static int hf_bscvlc_proprietary_data;
77
static int hf_bscvlc_hub_conn_state;
78
static int hf_bscvlc_accept_conns;
79
static int hf_bscvlc_max_bvlc_length;
80
static int hf_bscvlc_max_npdu_length;
81
static int hf_bscvlc_function;
82
static int hf_bscvlc_result;
83
static int hf_bscvlc_error_class;
84
static int hf_bscvlc_error_code;
85
static int hf_bscvlc_result_data;
86
static int hf_bscvlc_uris;
87
static int hf_bscvlc_msg_id;
88
static int hf_bscvlc_orig_vmac;
89
static int hf_bscvlc_dest_vmac;
90
static int hf_bscvlc_connect_vmac;
91
static int hf_bscvlc_connect_uuid;
92
static int hf_bscvlc_identity_device_id;
93
static int hf_bscvlc_hello_opt;
94
static int hf_bscvlc_hello_opt_identity_relay;
95
96
static dissector_table_t bvlc_dissector_table;
97
static dissector_table_t bscvlc_dissector_table;
98
static dissector_table_t bvlc_ipv6_dissector_table;
99
static dissector_handle_t bvlc_handle;
100
static dissector_handle_t bscvlc_handle;
101
102
static const value_string bvlc_function_names[] = {
103
  { 0x00, "BVLC-Result" },
104
  { 0x01, "Write-Broadcast-Distribution-Table" },
105
  { 0x02, "Read-Broadcast-Distribution-Table" },
106
  { 0x03, "Read-Broadcast-Distribution-Table-Ack" },
107
  { 0x04, "Forwarded-NPDU" },
108
  { 0x05, "Register-Foreign-Device" },
109
  { 0x06, "Read-Foreign-Device-Table" },
110
  { 0x07, "Read-Foreign-Device-Table-Ack" },
111
  { 0x08, "Delete-Foreign-Device-Table-Entry" },
112
  { 0x09, "Distribute-Broadcast-To-Network" },
113
  { 0x0a, "Original-Unicast-NPDU" },
114
  { 0x0b, "Original-Broadcast-NPDU" },
115
  { 0x0c, "Secured-BVLL" },
116
  { 0, NULL }
117
};
118
119
static const value_string bscvlc_function_names[] = {
120
  { 0x00, "BVLC-Result" },
121
  { 0x01, "Encapsulated-NPDU" },
122
  { 0x02, "Address-Resolution" },
123
  { 0x03, "Address-Resolution-ACK" },
124
  { 0x04, "Advertisement" },
125
  { 0x05, "Advertisement-Solicitation" },
126
  { 0x06, "Connect-Request" },
127
  { 0x07, "Connect-Accept" },
128
  { 0x08, "Disconnect-Request" },
129
  { 0x09, "Disconnect-ACK" },
130
  { 0x0A, "Heartbeat-Request" },
131
  { 0x0B, "Heartbeat-ACK" },
132
  { 0x0C, "Proprietary-Message" },
133
  { 0, NULL }
134
};
135
136
static const value_string bvlc_result_names[] = {
137
  { 0x00, "Successful completion" },
138
  { 0x10, "Write-Broadcast-Distribution-Table NAK" },
139
  { 0x20, "Read-Broadcast-Distribution-Table NAK" },
140
  { 0x30, "Register-Foreign-Device NAK" },
141
  { 0x40, "Read-Foreign-Device-Table NAK" },
142
  { 0x50, "Delete-Foreign-Device-Table-Entry NAK" },
143
  { 0x60, "Distribute-Broadcast-To-Network NAK" },
144
  { 0,    NULL }
145
};
146
147
static const value_string bscvlc_result_names[] = {
148
  { 0x00, "Successful completion (ACK)" },
149
  { 0x01, "Completion failed (NAK)" },
150
  { 0,    NULL }
151
};
152
153
static const value_string bvlc_ipv6_function_names[] = {
154
  { 0x00, "BVLC-Result", },
155
  { 0x01, "Original-Unicast-NPDU", },
156
  { 0x02, "Original-Broadcast-NPDU", },
157
  { 0x03, "Address-Resolution", },
158
  { 0x04, "Forwarded-Address-Resolution", },
159
  { 0x05, "Address-Resolution-ACK", },
160
  { 0x06, "Virtual-Address-Resolution", },
161
  { 0x07, "Virtual-Address-Resolution-ACK", },
162
  { 0x08, "Forwarded-NPDU", },
163
  { 0x09, "Register-Foreign-Device", },
164
  { 0x0A, "Delete-Foreign-Device-Table-Entry", },
165
  { 0x0B, "Secure-BVLL", },
166
  { 0x0C, "Distribute-Broadcast-To-Network", },
167
  { 0, NULL }
168
};
169
170
static const value_string bvlc_ipv6_result_names[] = {
171
  { 0x00, "Successful completion" },
172
  { 0x30, "Address-Resolution NAK" },
173
  { 0x60, "Virtual-Address-Resolution NAK" },
174
  { 0x90, "Register-Foreign-Device NAK" },
175
  { 0xA0, "Delete-Foreign-Device-Table-Entry NAK" },
176
  { 0xC0, "Distribute-Broadcast-To-Network NAK" },
177
  { 0, NULL }
178
};
179
180
static const value_string bscvlc_header_type_names[] = {
181
  { 0x01, "Secure Path" },
182
  { 0x02, "Hello" },
183
  { 0x03, "Identity" },
184
  { 0x04, "Hint" },
185
  { 0x05, "Token" },
186
  { 0x1F, "Proprietary Header Option" },
187
  { 0,    NULL }
188
};
189
190
static const value_string bscvlc_hub_conn_state_names[] = {
191
  { 0x00, "No hub connection" },
192
  { 0x01, "Connected to primary hub" },
193
  { 0x02, "Connected to failover hub" },
194
  { 0,    NULL }
195
};
196
197
static const value_string bscvlc_hub_accept_conns_names[] = {
198
  { 0x00, "The node does not support accepting direct connections" },
199
  { 0x01, "The node supports accepting direct connections" },
200
  { 0,    NULL }
201
};
202
203
static int ett_bvlc;
204
static int ett_bscvlc;
205
static int ett_bscvlc_ctrl;
206
static int ett_bscvlc_hdr;
207
static int ett_bdt;
208
static int ett_fdt;
209
210
0
#define BACNET_IP_ANNEX_J   0x81
211
3
#define BACNET_IPV6_ANNEX_U   0x82
212
213
static const value_string bvlc_types[] = {
214
  { BACNET_IP_ANNEX_J,  "BACnet/IP (Annex J)" },
215
  { BACNET_IPV6_ANNEX_U,  "BACnet/IPV6 (Annex U)" },
216
  { 0, NULL }
217
};
218
219
15
#define BSCVLC_CONTROL_DATA_OPTION    0x01
220
15
#define BSCVLC_CONTROL_DEST_OPTION    0x02
221
15
#define BSCVLC_CONTROL_DEST_ADDRESS   0x04
222
15
#define BSCVLC_CONTROL_ORIG_ADDRESS   0x08
223
15
#define BSCVLC_CONTROL_RESERVED     0xF0
224
225
static const true_false_string control_data_option_set_high = {
226
  "Data Options field is present.",
227
  "Data Options field is absent."
228
};
229
230
static const true_false_string control_destination_option_set_high = {
231
  "Destination Options field is present.",
232
  "Destination Options field is absent."
233
};
234
235
static const true_false_string control_destination_address_set_high = {
236
  "Destination Virtual Address is present.",
237
  "Destination Virtual Address is absent."
238
};
239
240
static const true_false_string control_orig_address_set_high = {
241
  "Originating Virtual Address is present.",
242
  "Originating Virtual Address is absent."
243
};
244
245
static const true_false_string control_reserved_set_high = {
246
  "Shall be zero, but is not.",
247
  "Shall be zero and is zero."
248
};
249
250
/* BSCVLC Header option bits */
251
15
#define BSCVLC_HDR_MORE_OPTIONS_FOLLOW            0x80
252
15
#define BSCVLC_HDR_MUST_UNDERSTAND                0x40
253
0
#define BSCVLC_HDR_EVERY_SEGMENT                  0x40
254
15
#define BSCVLC_HDR_DATA_PRESENT                   0x20
255
15
#define BSCVLC_HDR_OPTION_TYPE_MASK               0x1F
256
257
/* BSCVLC Header options and their bits */
258
0
#define BSCVLC_HDR_OPT_SECURE_PATH                0x01  /* only data option */
259
0
#define BSCVLC_HDR_OPT_HELLO                      0x02  /* only destination option */
260
#define BSCVLC_HDR_OPT_HELLO_BIT_IDENT_RELAY      0x01  /* only with the connect request */
261
0
#define BSCVLC_HDR_OPT_IDENTITY                   0x03  /* only data option */
262
0
#define BSCVLC_HDR_OPT_HINT                       0x04  /* only data option */
263
0
#define BSCVLC_HDR_OPT_TOKEN                      0x05  /* only data option */
264
0
#define BSCVLC_HDR_OPT_PROPRIETARY                0x1F  /* data or destination option */
265
266
267
static const true_false_string header_opt_data_set_high = {
268
  "The 'Header Length' and 'Header Data' fields are present.",
269
  "The 'Header Length' and 'Header Data' fields are absent."
270
};
271
272
static const true_false_string header_opt_must_understand_set_high = {
273
  "This header option must be understood for consuming the message.",
274
  "This header option can be ignored if not understood."
275
};
276
277
static const true_false_string header_opt_more_set_high = {
278
  "Another header option follows in the current header option list.",
279
  "This is the last header option in the current header option list."
280
};
281
282
15
#define BSCVLC_HELLO_IDENTITY_RELAY   0x01
283
284
static const true_false_string hello_opt_identity_relay_set_high = {
285
  "Identity relay is allowed.",
286
  "Identity relay is forbidden."
287
};
288
289
static int * const bscvlc_hello1_opt_flags[] = {
290
  &hf_bscvlc_hello_opt_identity_relay,
291
  NULL
292
};
293
294
static const value_string
295
BACnetErrorClass [] = {
296
    { 0, "device" },
297
    { 1, "object" },
298
    { 2, "property" },
299
    { 3, "resources" },
300
    { 4, "security" },
301
    { 5, "services" },
302
    { 6, "vt" },
303
    { 7, "communication" },
304
    { 0, NULL }
305
/* Enumerated values 0-63 are reserved for definition by ASHRAE.
306
   Enumerated values64-65535 may be used by others subject to
307
   the procedures and constraints described in Clause 23. */
308
};
309
310
static const value_string
311
BACnetErrorCode[] = {
312
    {   0, "other"},
313
    {   1, "authentication-failed"},
314
    {   2, "configuration-in-progress"},
315
    {   3, "device-busy"},
316
    {   4, "dynamic-creation-not-supported"},
317
    {   5, "file-access-denied"},
318
    {   6, "incompatible-security-levels"},
319
    {   7, "inconsistent-parameters"},
320
    {   8, "inconsistent-selection-criterion"},
321
    {   9, "invalid-data-type"},
322
    {  10, "invalid-file-access-method"},
323
    {  11, "invalid-file-start-position"},
324
    {  12, "invalid-operator-name"},
325
    {  13, "invalid-parameter-data-type"},
326
    {  14, "invalid-time-stamp"},
327
    {  15, "key-generation-error"},
328
    {  16, "missing-required-parameter"},
329
    {  17, "no-objects-of-specified-type"},
330
    {  18, "no-space-for-object"},
331
    {  19, "no-space-to-add-list-element"},
332
    {  20, "no-space-to-write-property"},
333
    {  21, "no-vt-sessions-available"},
334
    {  22, "property-is-not-a-list"},
335
    {  23, "object-deletion-not-permitted"},
336
    {  24, "object-identifier-already-exists"},
337
    {  25, "operational-problem"},
338
    {  26, "password-failure"},
339
    {  27, "read-access-denied"},
340
    {  28, "security-not-supported"},
341
    {  29, "service-request-denied"},
342
    {  30, "timeout"},
343
    {  31, "unknown-object"},
344
    {  32, "unknown-property"},
345
    {  33, "removed enumeration"},
346
    {  34, "unknown-vt-class"},
347
    {  35, "unknown-vt-session"},
348
    {  36, "unsupported-object-type"},
349
    {  37, "value-out-of-range"},
350
    {  38, "vt-session-already-closed"},
351
    {  39, "vt-session-termination-failure"},
352
    {  40, "write-access-denied"},
353
    {  41, "character-set-not-supported"},
354
    {  42, "invalid-array-index"},
355
    {  43, "cov-subscription-failed"},
356
    {  44, "not-cov-property"},
357
    {  45, "optional-functionality-not-supported"},
358
    {  46, "invalid-configuration-data"},
359
    {  47, "datatype-not-supported"},
360
    {  48, "duplicate-name"},
361
    {  49, "duplicate-object-id"},
362
    {  50, "property-is-not-an-array"},
363
    {  51, "abort - buffer - overflow" },
364
    {  52, "abort - invalid - apdu - in - this - state" },
365
    {  53, "abort - preempted - by - higher - priority - task" },
366
    {  54, "abort - segmentation - not - supported" },
367
    {  55, "abort - proprietary" },
368
    {  56, "abort - other" },
369
    {  57, "reject - invalid - tag" },
370
    {  58, "reject - network - down" },
371
    {  59, "reject - buffer - overflow" },
372
    {  60, "reject - inconsistent - parameters" },
373
    {  61, "reject - invalid - parameter - data - type" },
374
    {  62, "reject - invalid - tag" },
375
    {  63, "reject - missing - required - parameter" },
376
    {  64, "reject - parameter - out - of - range" },
377
    {  65, "reject - too - many - arguments" },
378
    {  66, "reject - undefined - enumeration" },
379
    {  67, "reject - unrecognized - service" },
380
    {  68, "reject - proprietary" },
381
    {  69, "reject - other" },
382
    {  70, "unknown - device" },
383
    {  71, "unknown - route" },
384
    {  72, "value - not - initialized" },
385
    {  73, "invalid-event-state"},
386
    {  74, "no-alarm-configured"},
387
    {  75, "log-buffer-full"},
388
    {  76, "logged-value-purged"},
389
    {  77, "no-property-specified"},
390
    {  78, "not-configured-for-triggered-logging"},
391
    {  79, "unknown-subscription"},
392
    {  80, "parameter-out-of-range"},
393
    {  81, "list-element-not-found"},
394
    {  82, "busy"},
395
    {  83, "communication-disabled"},
396
    {  84, "success"},
397
    {  85, "access-denied"},
398
    {  86, "bad-destination-address"},
399
    {  87, "bad-destination-device-id"},
400
    {  88, "bad-signature"},
401
    {  89, "bad-source-address"},
402
    {  90, "bad-timestamp"},
403
    {  91, "cannot-use-key"},
404
    {  92, "cannot-verify-message-id"},
405
    {  93, "correct-key-revision"},
406
    {  94, "destination-device-id-required"},
407
    {  95, "duplicate-message"},
408
    {  96, "encryption-not-configured"},
409
    {  97, "encryption-required"},
410
    {  98, "incorrect-key"},
411
    {  99, "invalid-key-data"},
412
    { 100, "key-update-in-progress"},
413
    { 101, "malformed-message"},
414
    { 102, "not-key-server"},
415
    { 103, "security-not-configured"},
416
    { 104, "source-security-required"},
417
    { 105, "too-many-keys"},
418
    { 106, "unknown-authentication-type"},
419
    { 107, "unknown-key"},
420
    { 108, "unknown-key-revision"},
421
    { 109, "unknown-source-message"},
422
    { 110, "not-router-to-dnet"},
423
    { 111, "router-busy"},
424
    { 112, "unknown-network-message"},
425
    { 113, "message-too-long"},
426
    { 114, "security-error"},
427
    { 115, "addressing-error"},
428
    { 116, "write-bdt-failed"},
429
    { 117, "read-bdt-failed"},
430
    { 118, "register-foreign-device-failed"},
431
    { 119, "read-fdt-failed"},
432
    { 120, "delete-fdt-entry-failed"},
433
    { 121, "distribute-broadcast-failed"},
434
    { 122, "unknown-file-size"},
435
    { 123, "abort-apdu-too-long"},
436
    { 124, "abort-application-exceeded-reply-time"},
437
    { 125, "abort-out-of-resources"},
438
    { 126, "abort-tsm-timeout"},
439
    { 127, "abort-window-size-out-of-range"},
440
    { 128, "file-full"},
441
    { 129, "inconsistent-configuration"},
442
    { 130, "inconsistent-object-type"},
443
    { 131, "internal-error"},
444
    { 132, "not-configured"},
445
    { 133, "out-of-memory"},
446
    { 134, "value-too-long"},
447
    { 135, "abort-insufficient-security"},
448
    { 136, "abort-security-error"},
449
    { 137, "duplicate-entry"},
450
    { 138, "invalid-value-in-this-state"},
451
    { 139, "invalid-operation-in-this-state"},
452
    { 140, "list-item-not-numbered"},
453
    { 141, "list-item-not-timestamped"},
454
    { 142, "invalid-data-encoding"},
455
    { 143, "bvlc-function-unknown"},
456
    { 144, "bvlc-proprietary-function-unknown"},
457
    { 145, "header-encoding-error"},
458
    { 146, "header-not-understood"},
459
    { 147, "message-incomplete"},
460
    { 148, "not-a-bacnet-sc-hub"},
461
    { 149, "payload-expected"},
462
    { 150, "unexpected-data"},
463
    { 151, "node-duplicate-vmac"},
464
    { 152, "http-unexpected-response-code"},
465
    { 153, "http-no-upgrade"},
466
    { 154, "http-resource-not-local"},
467
    { 155, "http-proxy-authentication-failed"},
468
    { 156, "http-response-timeout"},
469
    { 157, "http-response-syntax-error"},
470
    { 158, "http-response-value-error"},
471
    { 159, "http-response-missing-header"},
472
    { 160, "http-websocket-header-error"},
473
    { 161, "http-upgrade-required"},
474
    { 162, "http-upgrade-error"},
475
    { 163, "http-temporary-unavailable"},
476
    { 164, "http-not-a-server"},
477
    { 165, "http-error"},
478
    { 166, "websocket-scheme-not-supported"},
479
    { 167, "websocket-unknown-control-message"},
480
    { 168, "websocket-close-error"},
481
    { 169, "websocket-closed-by-peer"},
482
    { 170, "websocket-endpoint-leaves"},
483
    { 171, "websocket-protocol-error"},
484
    { 172, "websocket-data-not-accepted"},
485
    { 173, "websocket-closed-abnormally"},
486
    { 174, "websocket-data-inconsistent"},
487
    { 175, "websocket-data-against-policy"},
488
    { 176, "websocket-frame-too-long"},
489
    { 177, "websocket-extension-missing"},
490
    { 178, "websocket-request-unavailable"},
491
    { 179, "websocket-error"},
492
    { 180, "tls-client-certificate-error"},
493
    { 181, "tls-server-certificate-error"},
494
    { 182, "tls-client-authentication-failed"},
495
    { 183, "tls-server-authentication-failed"},
496
    { 184, "tls-client-certificate-expired"},
497
    { 185, "tls-server-certificate-expired"},
498
    { 186, "tls-client-certificate-revoked"},
499
    { 187, "tls-server-certificate-revoked"},
500
    { 188, "tls-error"},
501
    { 189, "dns-unavailable"},
502
    { 190, "dns-name-resolution-failed"},
503
    { 191, "dns-resolver-failure"},
504
    { 192, "dns-error"},
505
    { 193, "tcp-connect-timeout"},
506
    { 194, "tcp-connection-refused"},
507
    { 195, "tcp-closed-by-local"},
508
    { 196, "tcp-closed-other"},
509
    { 197, "tcp-error"},
510
    { 198, "ip-address-not-reachable"},
511
    { 199, "ip-error"},
512
    { 200, "certificate-expired"},
513
    { 201, "certificate-invalid"},
514
    { 202, "certificate-malformed"},
515
    { 203, "certificate-revoked"},
516
    { 204, "unknown-key"},
517
    { 205, "referenced-port-in-error"},
518
    { 206, "not-enabled"},
519
    { 207, "adjust-scope-required"},
520
    { 208, "auth-scope-required"},
521
    { 209, "bind-scope-required"},
522
    { 210, "config-scope-required"},
523
    { 211, "control-scope-required"},
524
    { 212, "extended-scope-required"},
525
    { 213, "incorrect-client"},
526
    { 214, "install-scope-required"},
527
    { 215, "insufficient-scope"},
528
    { 216, "no-default-scope"},
529
    { 217, "no-policy"},
530
    { 218, "revoked-token"},
531
    { 219, "override-scope-required"},
532
    { 220, "inactive-token"},
533
    { 221, "unknown-audience"},
534
    { 222, "unknown-client"},
535
    { 223, "unknown-scope"},
536
    { 224, "view-scope-required"},
537
    { 225, "incorrect-audience"},
538
    { 226, "incorrect-client-origin"},
539
    { 227, "invalid-array-size"},
540
    { 228, "incorrect-issuer"},
541
    { 229, "invalid-token"},
542
    { 0,   NULL}
543
/* Enumerated values 0-255 are reserved for definition by ASHRAE.
544
   Enumerated values 256-65535 may be used by others subject to the
545
   procedures and constraints described in Clause 23. */
546
};
547
static value_string_ext BACnetErrorCode_ext = VALUE_STRING_EXT_INIT(BACnetErrorCode);
548
549
550
551
static int * const bscvlc_control_flags[] = {
552
  &hf_bscvlc_control_data_option,
553
  &hf_bscvlc_control_destination_option,
554
  &hf_bscvlc_control_destination_address,
555
  &hf_bscvlc_control_origin_address,
556
  &hf_bscvlc_control_reserved,
557
  NULL
558
};
559
560
static int * const bscvlc_header_flags[] = {
561
  &hf_bscvlc_header_opt_type,
562
  &hf_bscvlc_header_opt_data,
563
  &hf_bscvlc_header_opt_must_understand,
564
  &hf_bscvlc_header_opt_more,
565
  NULL
566
};
567
568
static int
569
// NOLINTNEXTLINE(misc-no-recursion)
570
dissect_ipv4_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
571
0
{
572
573
0
  proto_item *ti;
574
0
  proto_item *ti_bdt;
575
0
  proto_item *ti_fdt;
576
0
  proto_tree *bvlc_tree;
577
0
  proto_tree *bdt_tree; /* Broadcast Distribution Table */
578
0
  proto_tree *fdt_tree; /* Foreign Device Table */
579
580
0
  unsigned offset;
581
0
  bool sec_decrypted;
582
0
  uint8_t bvlc_type;
583
0
  uint8_t bvlc_function;
584
0
  uint16_t bvlc_length;
585
0
  uint16_t packet_length;
586
0
  unsigned npdu_length;
587
0
  unsigned length_remaining;
588
0
  tvbuff_t *next_tvb;
589
590
0
  offset = 0;
591
592
0
  bvlc_type = tvb_get_uint8(tvb, offset);
593
0
  bvlc_function = tvb_get_uint8(tvb, offset + 1);
594
0
  packet_length = tvb_get_ntohs(tvb, offset + 2);
595
0
  length_remaining = tvb_reported_length_remaining(tvb, offset);
596
597
0
  if (bvlc_function > 0x08) {
598
    /*  We have a constant header length of BVLC of 4 in every
599
     *  BVLC-packet forewarding an NPDU. Beware: Changes in the
600
     *  BACnet-IP-standard may break this.
601
     */
602
0
    bvlc_length = 4;
603
0
  } else if (bvlc_function == 0x04) {
604
    /* 4 Bytes + 6 Bytes for B/IP Address of Originating Device */
605
0
    bvlc_length = 10;
606
0
  } else {
607
    /*  BVLC-packets with function below 0x09 contain
608
     *  routing-level data (e.g. Broadcast Distribution)
609
     *  but no NPDU for BACnet, so bvlc_length goes up to the end
610
     *  of the captured frame.
611
     */
612
0
    bvlc_length = packet_length;
613
0
  }
614
615
0
  if (bvlc_length < 4 || bvlc_length > packet_length) {
616
0
    return 0; /* reject */
617
0
  }
618
619
  /* Put the BVLC Type in the info column */
620
0
  col_append_fstr(pinfo->cinfo, COL_INFO, " BVLC Function %s ",
621
0
      val_to_str_const(bvlc_function, bvlc_function_names, "unknown"));
622
623
0
  ti = proto_tree_add_item(tree, proto_bvlc, tvb, 0, bvlc_length, ENC_NA);
624
0
  bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
625
0
  proto_tree_add_uint(bvlc_tree, hf_bvlc_type, tvb, offset, 1,
626
0
    bvlc_type);
627
0
  offset++;
628
0
  proto_tree_add_uint(bvlc_tree, hf_bvlc_function, tvb,
629
0
    offset, 1, bvlc_function);
630
0
  offset++;
631
0
  if (length_remaining != packet_length)
632
0
    proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
633
0
      2, bvlc_length,
634
0
      "%d of %d bytes (invalid length - expected %d bytes)",
635
0
      bvlc_length, packet_length, length_remaining);
636
0
  else
637
0
    proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
638
0
      2, bvlc_length, "%d of %d bytes BACnet packet length",
639
0
      bvlc_length, packet_length);
640
0
  offset += 2;
641
0
  switch (bvlc_function) {
642
0
  case 0x00: /* BVLC-Result */
643
    /* I don't know why the result code is encoded in 4 nibbles,
644
     * but only using one: 0x00r0. Shifting left 4 bits.
645
     */
646
    /* We should bitmask the result correctly when we have a
647
     * packet to dissect, see README.developer, 1.6.2, FID */
648
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_result_ip4, tvb,
649
0
      offset, 2, ENC_BIG_ENDIAN);
650
    /*offset += 2;*/
651
0
    break;
652
0
  case 0x01: /* Write-Broadcast-Distribution-Table */
653
0
  case 0x03: /* Read-Broadcast-Distribution-Table-Ack */
654
    /* List of BDT Entries: N*10-octet */
655
0
    ti_bdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb,
656
0
      offset, bvlc_length-4, ENC_NA);
657
0
    bdt_tree = proto_item_add_subtree(ti_bdt, ett_bdt);
658
    /* List of BDT Entries: N*10-octet */
659
0
    while ((bvlc_length - offset) > 9) {
660
0
      proto_tree_add_item(bdt_tree, hf_bvlc_bdt_ip,
661
0
        tvb, offset, 4, ENC_BIG_ENDIAN);
662
0
      offset += 4;
663
0
      proto_tree_add_item(bdt_tree, hf_bvlc_bdt_port,
664
0
        tvb, offset, 2, ENC_BIG_ENDIAN);
665
0
      offset += 2;
666
0
      proto_tree_add_item(bdt_tree,
667
0
        hf_bvlc_bdt_mask, tvb, offset, 4,
668
0
        ENC_NA);
669
0
      offset += 4;
670
0
    }
671
    /* We check this if we get a BDT-packet somewhere */
672
0
    break;
673
0
  case 0x02: /* Read-Broadcast-Distribution-Table */
674
    /* nothing to do here */
675
0
    break;
676
0
  case 0x05: /* Register-Foreign-Device */
677
    /* Time-to-Live 2-octets T, Time-to-Live T, in seconds */
678
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl,
679
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
680
    /*offset += 2;*/
681
0
    break;
682
0
  case 0x06: /* Read-Foreign-Device-Table */
683
    /* nothing to do here */
684
0
    break;
685
0
  case 0x07: /* Read-Foreign-Device-Table-Ack */
686
    /* List of FDT Entries: N*10-octet */
687
    /* N indicates the number of entries in the FDT whose
688
     * contents are being returned. Each returned entry
689
     * consists of the 6-octet B/IP address of the registrant;
690
     * the 2-octet Time-to-Live value supplied at the time of
691
     * registration; and a 2-octet value representing the
692
     * number of seconds remaining before the BBMD will purge
693
     * the registrant's FDT entry if no re-registration occurs.
694
     */
695
0
    ti_fdt = proto_tree_add_item(bvlc_tree, proto_bvlc, tvb,
696
0
      offset, bvlc_length -4, ENC_NA);
697
0
    fdt_tree = proto_item_add_subtree(ti_fdt, ett_fdt);
698
    /* List of FDT Entries: N*10-octet */
699
0
    while ((bvlc_length - offset) > 9) {
700
0
      proto_tree_add_item(fdt_tree, hf_bvlc_fdt_ip,
701
0
        tvb, offset, 4, ENC_BIG_ENDIAN);
702
0
      offset += 4;
703
0
      proto_tree_add_item(fdt_tree, hf_bvlc_fdt_port,
704
0
        tvb, offset, 2, ENC_BIG_ENDIAN);
705
0
      offset += 2;
706
0
      proto_tree_add_item(fdt_tree,
707
0
        hf_bvlc_fdt_ttl, tvb, offset, 2,
708
0
        ENC_BIG_ENDIAN);
709
0
      offset += 2;
710
0
      proto_tree_add_item(fdt_tree,
711
0
        hf_bvlc_fdt_timeout, tvb, offset, 2,
712
0
        ENC_BIG_ENDIAN);
713
0
      offset += 2;
714
0
    }
715
    /* We check this if we get a FDT-packet somewhere */
716
0
    break;
717
0
  case 0x08: /* Delete-Foreign-Device-Table-Entry */
718
    /* FDT Entry: 6-octets */
719
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_ip,
720
0
      tvb, offset, 4, ENC_BIG_ENDIAN);
721
0
    offset += 4;
722
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
723
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
724
    /*offset += 2;*/
725
0
    break;
726
0
  case 0x0C: /* Secure-BVLL */
727
0
    /*offset =*/ bacnet_dissect_sec_wrapper(tvb, pinfo, tree, offset, NULL, &sec_decrypted);
728
0
    if (!sec_decrypted) {
729
0
      call_data_dissector(tvb, pinfo, tree);
730
0
      return tvb_captured_length(tvb);
731
0
    }
732
0
    increment_dissection_depth(pinfo);
733
0
    dissect_ipv4_bvlc(tvb, pinfo, tree, data);
734
0
    decrement_dissection_depth(pinfo);
735
0
    break;
736
    /* We check this if we get a FDT-packet somewhere */
737
0
  case 0x04:  /* Forwarded-NPDU
738
       * Why is this 0x04? It would have been a better
739
       * idea to append all forewarded NPDUs at the
740
       * end of the function table in the B/IP-standard!
741
       */
742
    /* proto_tree_add_bytes_format(); */
743
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_ip,
744
0
      tvb, offset, 4, ENC_BIG_ENDIAN);
745
0
    offset += 4;
746
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fwd_port,
747
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
748
    /*offset += 2;*/
749
0
    break;
750
0
  default:
751
    /* Distribute-Broadcast-To-Network
752
     * Original-Unicast-NPDU
753
     * Original-Broadcast-NPDU
754
     * Going to the next dissector...
755
     */
756
0
    break;
757
0
  }
758
759
  /* Ok, no routing information BVLC packet. Dissect as
760
   * BACnet NPDU
761
   */
762
0
  npdu_length = packet_length - bvlc_length;
763
0
  next_tvb = tvb_new_subset_length(tvb, bvlc_length, npdu_length);
764
  /* Code from Guy Harris */
765
0
  if (!dissector_try_uint(bvlc_dissector_table,
766
0
    bvlc_function, next_tvb, pinfo, tree)) {
767
    /* Unknown function - dissect the payload as data */
768
0
    call_data_dissector(next_tvb, pinfo, tree);
769
0
  }
770
0
  return tvb_reported_length(tvb);
771
0
}
772
773
static int
774
// NOLINTNEXTLINE(misc-no-recursion)
775
dissect_ipv6_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
776
3
{
777
3
  proto_item *ti;
778
3
  proto_tree *bvlc_tree;
779
780
3
  unsigned offset;
781
3
  bool sec_decrypted;
782
3
  uint8_t bvlc_type;
783
3
  uint8_t bvlc_function;
784
3
  uint16_t bvlc_length = 0;
785
3
  uint16_t packet_length;
786
3
  unsigned npdu_length;
787
3
  unsigned length_remaining;
788
3
  tvbuff_t *next_tvb;
789
790
3
  offset = 0;
791
792
3
  bvlc_type = tvb_get_uint8(tvb, offset);
793
3
  bvlc_function = tvb_get_uint8(tvb, offset + 1);
794
3
  packet_length = tvb_get_ntohs(tvb, offset + 2);
795
3
  length_remaining = tvb_reported_length_remaining(tvb, offset);
796
797
3
  switch (bvlc_function) {
798
2
  case 0x00:
799
2
  case 0x09:
800
2
    bvlc_length = 9;
801
2
    break;
802
0
  case 0x01:
803
0
    bvlc_length = 10;
804
0
    break;
805
0
  case 0x02:
806
0
  case 0x06:
807
0
  case 0x0C:
808
0
    bvlc_length = 7;
809
0
    break;
810
0
  case 0x03:
811
0
  case 0x05:
812
0
  case 0x07:
813
0
    bvlc_length = 10;
814
0
    break;
815
0
  case 0x04:
816
0
    bvlc_length = 28;
817
0
    break;
818
0
  case 0x08:
819
0
  case 0x0A:
820
0
    bvlc_length = 25;
821
0
    break;
822
0
  case 0x0B:
823
0
    bvlc_length = 4;
824
0
    break;
825
1
  default:
826
1
    break;
827
3
  }
828
829
3
  if (bvlc_length > packet_length) {
830
1
    return 0; /* reject */
831
1
  }
832
833
  /* Put the BVLC Type in the info column */
834
2
  col_append_fstr(pinfo->cinfo, COL_INFO, " BVLC Function %s ",
835
2
      val_to_str_const(bvlc_function, bvlc_ipv6_function_names, "unknown"));
836
837
2
  ti = proto_tree_add_item(tree, proto_bvlc, tvb, 0,
838
2
    bvlc_length, ENC_NA);
839
2
  bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
840
  /* add the BVLC type */
841
2
  proto_tree_add_uint(bvlc_tree, hf_bvlc_type, tvb, offset, 1,
842
2
    bvlc_type);
843
2
  offset++;
844
  /* add the BVLC function */
845
2
  proto_tree_add_uint(bvlc_tree, hf_bvlc_ipv6_function, tvb,
846
2
    offset, 1, bvlc_function);
847
2
  offset++;
848
  /* add the length information */
849
2
  if (length_remaining != packet_length)
850
2
    proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
851
2
      2, bvlc_length,
852
2
      "%d of %d bytes (invalid length - expected %d bytes)",
853
2
      bvlc_length, packet_length, length_remaining);
854
0
  else
855
0
    proto_tree_add_uint_format_value(bvlc_tree, hf_bvlc_length, tvb, offset,
856
0
      2, bvlc_length,
857
0
      "%d of %d bytes BACnet packet length",
858
0
      bvlc_length, packet_length);
859
2
  offset += 2;
860
861
  /* add the optional present virtual source address */
862
2
  if (bvlc_function != 0x0B) {
863
2
    proto_tree_add_item(bvlc_tree, hf_bvlc_virt_source, tvb, offset,
864
2
      3, ENC_BIG_ENDIAN);
865
2
    offset += 3;
866
2
  }
867
868
  /* handle additional function parameters */
869
2
  switch (bvlc_function) {
870
1
  case 0x00: /* BVLC-Result */
871
1
    proto_tree_add_item(bvlc_tree, hf_bvlc_result_ip6, tvb,
872
1
      offset, 2, ENC_BIG_ENDIAN);
873
1
    offset += 2;
874
1
    break;
875
0
  case 0x01: /* Original-Unicast-NPDU */
876
0
  case 0x03: /* Address-Resolution */
877
0
  case 0x05: /* Address-Resolution-ACK */
878
0
  case 0x07: /* Virtual-Address-Resolution-ACK */
879
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_virt_dest, tvb, offset,
880
0
      3, ENC_BIG_ENDIAN);
881
0
    offset += 3;
882
0
    break;
883
0
  case 0x04: /* Forwarded-Address-Resolution */
884
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_virt_dest, tvb, offset,
885
0
      3, ENC_BIG_ENDIAN);
886
0
    offset += 3;
887
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_addr,
888
0
      tvb, offset, 16, ENC_NA);
889
0
    offset += 16;
890
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_port,
891
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
892
0
    offset += 2;
893
0
    break;
894
0
  case 0x08: /* Forwarded-NPDU */
895
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_addr,
896
0
      tvb, offset, 16, ENC_NA);
897
0
    offset += 16;
898
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_orig_source_port,
899
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
900
0
    offset += 2;
901
0
    break;
902
0
  case 0x06: /* Virtual-Address-Resolution */
903
0
    break;
904
0
  case 0x09: /* Register-Foreign-Device */
905
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_reg_ttl,
906
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
907
0
    offset += 2;
908
0
    break;
909
0
  case 0x0A: /* Delete-Foreign-Device-Table-Entry */
910
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_ipv6,
911
0
      tvb, offset, 16, ENC_NA);
912
0
    offset += 16;
913
0
    proto_tree_add_item(bvlc_tree, hf_bvlc_fdt_port,
914
0
      tvb, offset, 2, ENC_BIG_ENDIAN);
915
0
    offset += 2;
916
0
    break;
917
0
  case 0x0B: /* Secure-BVLL */
918
0
    offset = bacnet_dissect_sec_wrapper(tvb, pinfo, tree, offset, NULL, &sec_decrypted);
919
0
    if (!sec_decrypted) {
920
0
      call_data_dissector(tvb, pinfo, tree);
921
0
      return tvb_captured_length(tvb);
922
0
    }
923
0
    increment_dissection_depth(pinfo);
924
0
    dissect_ipv6_bvlc(tvb, pinfo, tree, data);
925
0
    decrement_dissection_depth(pinfo);
926
0
    break;
927
0
  case 0x02: /* Original-Broadcast-NPDU */
928
0
  case 0x0c: /* Distribute-Broadcast-To-Network */
929
1
  default:
930
    /*
931
     * Going to the next dissector...
932
     */
933
1
    break;
934
2
  }
935
936
  /* Ok, no routing information BVLC packet. Dissect as
937
   * BACnet NPDU
938
   */
939
1
  npdu_length = packet_length - offset;
940
1
  next_tvb = tvb_new_subset_length(tvb, offset, npdu_length);
941
  /* Code from Guy Harris */
942
1
  if ( ! dissector_try_uint(bvlc_ipv6_dissector_table,
943
1
    bvlc_function, next_tvb, pinfo, tree)) {
944
    /* Unknown function - dissect the payload as data */
945
1
    call_data_dissector(next_tvb, pinfo, tree);
946
1
  }
947
948
1
  return tvb_reported_length(tvb);
949
2
}
950
951
static int
952
dissect_bvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
953
4
{
954
4
  uint8_t bvlc_type;
955
4
  unsigned ret = 0;
956
957
4
  bvlc_type = tvb_get_uint8(tvb, 0);
958
959
  /*
960
   * Simple sanity check - make sure the type is one we know about.
961
   */
962
4
  if (try_val_to_str(bvlc_type, bvlc_types) == NULL)
963
1
    return 0;
964
965
3
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "BVLC");
966
3
  col_set_str(pinfo->cinfo, COL_INFO, "BACnet Virtual Link Control");
967
968
3
  switch (bvlc_type)
969
3
  {
970
0
  case BACNET_IP_ANNEX_J:
971
0
    ret = dissect_ipv4_bvlc(tvb, pinfo, tree, data);
972
0
    break;
973
3
  case BACNET_IPV6_ANNEX_U:
974
3
    ret = dissect_ipv6_bvlc(tvb, pinfo, tree, data);
975
3
    break;
976
3
  }
977
978
2
  return ret;
979
3
}
980
981
static int
982
dissect_bscvlc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
983
0
{
984
0
  proto_item *ti;
985
0
  proto_tree *bvlc_tree;
986
0
  tvbuff_t *next_tvb;
987
0
  int offset;
988
0
  int start;
989
0
  int bvlc_length;
990
0
  int packet_length;
991
0
  int npdu_length = 0;
992
0
  uint8_t bvlc_function;
993
0
  uint8_t bvlc_control;
994
0
  uint8_t bvlc_result;
995
0
  uint8_t hdr_byte;
996
0
  uint8_t option;
997
0
  unsigned bvlc_message_id;
998
0
  bool bMustSegment;
999
0
  bool bMoreFlag;
1000
0
  bool bDataFlag;
1001
0
  const char *pszUnderstand;
1002
0
  const char *pszOption;
1003
0
  proto_tree *subtree;
1004
1005
  /* Calculate length of BSCVLC block to get remaining payload length */
1006
0
  offset = 0;
1007
1008
0
  packet_length = tvb_reported_length_remaining(tvb, offset);
1009
0
  if(packet_length < 4)
1010
0
    return 0; /* reject */
1011
1012
  /* Fix part of the header first */
1013
0
  bvlc_function = tvb_get_uint8(tvb, offset++);
1014
0
  bvlc_control = tvb_get_uint8(tvb, offset++);
1015
0
  bvlc_message_id = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
1016
0
  offset += 2;
1017
1018
  /* Variable part of the header next */
1019
0
  bvlc_length = offset;
1020
1021
0
  if ((bvlc_control & BSCVLC_CONTROL_ORIG_ADDRESS) != 0)
1022
0
    bvlc_length += 6;
1023
1024
0
  if ((bvlc_control & BSCVLC_CONTROL_DEST_ADDRESS) != 0)
1025
0
    bvlc_length += 6;
1026
1027
0
  if ((bvlc_control & BSCVLC_CONTROL_DEST_OPTION) != 0)
1028
0
  {
1029
0
    bMoreFlag = true;
1030
1031
0
    while(tvb_reported_length_remaining(tvb, bvlc_length) > 0 &&
1032
0
          (hdr_byte = tvb_get_uint8(tvb, bvlc_length)) != 0 && bMoreFlag)
1033
0
    {
1034
      /* get flags and type... */
1035
0
      bMoreFlag = (hdr_byte & BSCVLC_HDR_MORE_OPTIONS_FOLLOW);
1036
0
      bDataFlag = (hdr_byte & BSCVLC_HDR_DATA_PRESENT);
1037
0
      bvlc_length++;
1038
1039
0
      if(bDataFlag)
1040
0
      {
1041
0
        npdu_length = (int)(tvb_get_uint8(tvb, bvlc_length++) << 8);
1042
0
        npdu_length += (int)tvb_get_uint8(tvb, bvlc_length++);
1043
0
        bvlc_length += npdu_length;
1044
0
      }
1045
0
    }
1046
0
  }
1047
1048
0
  if ((bvlc_control & BSCVLC_CONTROL_DATA_OPTION) != 0)
1049
0
  {
1050
0
    bMoreFlag = true;
1051
1052
0
    while(tvb_reported_length_remaining(tvb, bvlc_length) > 0 &&
1053
0
          (hdr_byte = tvb_get_uint8(tvb, bvlc_length)) != 0 && bMoreFlag)
1054
0
    {
1055
      /* get flags and type... */
1056
0
      bMoreFlag= (hdr_byte & BSCVLC_HDR_MORE_OPTIONS_FOLLOW);
1057
0
      bDataFlag= (hdr_byte & BSCVLC_HDR_DATA_PRESENT);
1058
0
      bvlc_length++;
1059
1060
0
      if(bDataFlag)
1061
0
      {
1062
0
        npdu_length = (int)(tvb_get_uint8(tvb, bvlc_length++) << 8);
1063
0
        npdu_length += (int)tvb_get_uint8(tvb, bvlc_length++);
1064
0
        bvlc_length += npdu_length;
1065
0
      }
1066
0
    }
1067
0
  }
1068
1069
  /* Now add the BSCVLC payload size for specified function */
1070
0
  switch (bvlc_function)
1071
0
  {
1072
0
  case 0x00: /* BVLC-Result */
1073
0
  case 0x03: /* Address-Resolution-ACK */
1074
0
  case 0x0C: /* Proprietary-Message */
1075
    /* complete packet length because of optional present variable length error data
1076
       but no length encoded for it in the structure of this frame */
1077
0
    bvlc_length = packet_length;
1078
0
    break;
1079
0
  case 0x02: /* Address-Resolution */
1080
0
  case 0x05: /* Advertisement-Solicitation */
1081
0
  case 0x08: /* Disconnect-Request */
1082
0
  case 0x09: /* Disconnect-ACK */
1083
0
  case 0x0A: /* Heartbeat-Request */
1084
0
  case 0x0B: /* Heartbeat-ACK */
1085
    /* No additional payload here */
1086
0
    break;
1087
0
  case 0x04: /* Advertisement */
1088
0
    bvlc_length += 6;
1089
0
    break;
1090
0
  case 0x06: /* Connect-Request */
1091
0
  case 0x07: /* Connect-Accept */
1092
0
    bvlc_length += 26;
1093
0
    break;
1094
0
  case 0x01: /* Encapsulated-NPDU */
1095
0
  default:
1096
    /* The additional payload will be decoded elsewhere */
1097
0
    break;
1098
0
  }
1099
1100
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "BSCVLC");
1101
0
  col_set_str(pinfo->cinfo, COL_INFO, "BACnet Secure Connect Virtual Link Control");
1102
1103
  /* Put the BSCVLC Type and Message ID in the info column */
1104
0
  col_append_fstr(pinfo->cinfo, COL_INFO, " BSCVLC Function %s Message-ID %u",
1105
0
      val_to_str_const(bvlc_function, bscvlc_function_names, "unknown"), bvlc_message_id);
1106
1107
  /* Fill the tree... */
1108
0
  offset = 0;
1109
0
  ti = proto_tree_add_item(tree, proto_bscvlc, tvb, 0, bvlc_length, ENC_NA);
1110
0
  bvlc_tree = proto_item_add_subtree(ti, ett_bvlc);
1111
1112
0
  proto_tree_add_uint(bvlc_tree, hf_bscvlc_function, tvb,
1113
0
    offset, 1, bvlc_function);
1114
0
  offset++;
1115
0
  proto_tree_add_bitmask(bvlc_tree, tvb, offset, hf_bscvlc_control,
1116
0
        ett_bscvlc_ctrl, bscvlc_control_flags, ENC_NA);
1117
0
  offset ++;
1118
0
  proto_tree_add_uint(bvlc_tree, hf_bscvlc_msg_id, tvb,
1119
0
    offset, 2, bvlc_message_id);
1120
0
  offset += 2;
1121
1122
0
  if ((bvlc_control & BSCVLC_CONTROL_ORIG_ADDRESS) != 0)
1123
0
  {
1124
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " SMAC %s", tvb_bytes_to_str(pinfo->pool, tvb, offset, 6));
1125
1126
0
    proto_tree_add_item(bvlc_tree, hf_bscvlc_orig_vmac, tvb, offset, 6, ENC_NA);
1127
0
    offset += 6;
1128
0
  }
1129
1130
0
  if ((bvlc_control & BSCVLC_CONTROL_DEST_ADDRESS) != 0)
1131
0
  {
1132
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " DMAC %s", tvb_bytes_to_str(pinfo->pool, tvb, offset, 6));
1133
1134
0
    proto_tree_add_item(bvlc_tree, hf_bscvlc_dest_vmac, tvb, offset, 6, ENC_NA);
1135
0
    offset += 6;
1136
0
  }
1137
1138
0
  if ((bvlc_control & BSCVLC_CONTROL_DEST_OPTION) != 0)
1139
0
  {
1140
0
    bMoreFlag = true;
1141
1142
0
    while(tvb_reported_length_remaining(tvb, offset) > 0 &&
1143
0
          (hdr_byte = tvb_get_uint8(tvb, offset)) != 0 && bMoreFlag)
1144
0
    {
1145
      /* get flags and type... */
1146
0
      option = (hdr_byte & BSCVLC_HDR_OPTION_TYPE_MASK);
1147
0
      bMustSegment = (hdr_byte & BSCVLC_HDR_MUST_UNDERSTAND);
1148
0
      bMoreFlag = (hdr_byte & BSCVLC_HDR_MORE_OPTIONS_FOLLOW);
1149
0
      bDataFlag = (hdr_byte & BSCVLC_HDR_DATA_PRESENT);
1150
0
      start = offset;
1151
1152
0
      offset++;
1153
1154
0
      if(bDataFlag)
1155
0
      {
1156
0
        npdu_length = (int)(tvb_get_uint8(tvb, offset++) << 8);
1157
0
        npdu_length += (int)tvb_get_uint8(tvb, offset++);
1158
0
        offset += npdu_length;
1159
0
      }
1160
1161
0
      if(bMustSegment)
1162
0
        pszUnderstand = "must understand";
1163
0
      else
1164
0
        pszUnderstand = "optional";
1165
1166
0
      switch(option)
1167
0
      {
1168
0
      case BSCVLC_HDR_OPT_SECURE_PATH:
1169
0
        pszOption = "secure path";
1170
0
        break;
1171
0
      case BSCVLC_HDR_OPT_HELLO:
1172
0
        pszOption = "hello";
1173
0
        break;
1174
0
      case BSCVLC_HDR_OPT_IDENTITY:
1175
0
        pszOption = "identity";
1176
0
        break;
1177
0
      case BSCVLC_HDR_OPT_HINT:
1178
0
        pszOption = "hint";
1179
0
        break;
1180
0
      case BSCVLC_HDR_OPT_TOKEN:
1181
0
        pszOption = "token";
1182
0
        break;
1183
0
      case BSCVLC_HDR_OPT_PROPRIETARY:
1184
0
        pszOption = "proprietary";
1185
0
        break;
1186
0
      default:
1187
0
        pszOption = "reserved by ASHREA";
1188
0
        break;
1189
0
      }
1190
1191
0
      subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, start, offset - start,
1192
0
          ett_bscvlc_hdr, NULL, "Destination %s option %s", pszUnderstand, pszOption);
1193
0
      proto_tree_add_bitmask_value(subtree, tvb, start, hf_bscvlc_header,
1194
0
        ett_bscvlc_hdr, bscvlc_header_flags, hdr_byte);
1195
1196
0
      if(bDataFlag)
1197
0
      {
1198
0
        proto_tree_add_item(subtree, hf_bscvlc_header_length, tvb, start + 1, 2, ENC_BIG_ENDIAN);
1199
0
        switch(option)
1200
0
        {
1201
0
        case BSCVLC_HDR_OPT_HELLO:
1202
0
          proto_tree_add_bitmask_value(subtree, tvb, start + 3, hf_bscvlc_hello_opt,
1203
0
            ett_bscvlc_hdr, bscvlc_hello1_opt_flags, tvb_get_uint8(tvb, start + 3));
1204
0
          break;
1205
0
        case BSCVLC_HDR_OPT_IDENTITY:
1206
0
          proto_tree_add_item(subtree, hf_bscvlc_identity_device_id, tvb, start + 3, 3, ENC_BIG_ENDIAN);
1207
0
          break;
1208
0
        case BSCVLC_HDR_OPT_HINT:
1209
0
          bacnet_dissect_scope(tvb_new_subset_length(tvb, start, npdu_length + 3), pinfo, subtree, 3, "scope: ");
1210
0
          break;
1211
0
        case BSCVLC_HDR_OPT_TOKEN:
1212
0
          bacnet_dissect_token(tvb_new_subset_length(tvb, start, npdu_length + 3), pinfo, subtree, 3, "token: ");
1213
0
          break;
1214
0
        default:
1215
0
          proto_tree_add_item(subtree, hf_bscvlc_header_data, tvb, start + 3, npdu_length, ENC_NA);
1216
0
          break;
1217
0
        }
1218
0
      }
1219
0
    }
1220
0
  }
1221
1222
0
  if ((bvlc_control & BSCVLC_CONTROL_DATA_OPTION) != 0)
1223
0
  {
1224
0
    bMoreFlag = true;
1225
1226
0
    while(tvb_reported_length_remaining(tvb, offset) > 0 &&
1227
0
          (hdr_byte = tvb_get_uint8(tvb, offset)) != 0 && bMoreFlag)
1228
0
    {
1229
      /* get flags and type... */
1230
0
      option = (hdr_byte & BSCVLC_HDR_OPTION_TYPE_MASK);
1231
0
      bMustSegment = (hdr_byte & BSCVLC_HDR_EVERY_SEGMENT);
1232
0
      bMoreFlag = (hdr_byte & BSCVLC_HDR_MORE_OPTIONS_FOLLOW);
1233
0
      bDataFlag = (hdr_byte & BSCVLC_HDR_DATA_PRESENT);
1234
0
      start = offset;
1235
1236
0
      offset++;
1237
1238
0
      if(bDataFlag)
1239
0
      {
1240
0
        npdu_length = (int)(tvb_get_uint8(tvb, offset++) << 8);
1241
0
        npdu_length += (int)tvb_get_uint8(tvb, offset++);
1242
0
        offset += npdu_length;
1243
0
      }
1244
1245
0
      if(bMustSegment)
1246
0
        pszUnderstand = "must understand";
1247
0
      else
1248
0
        pszUnderstand = "optional";
1249
1250
0
      switch(option)
1251
0
      {
1252
0
      case BSCVLC_HDR_OPT_SECURE_PATH:
1253
0
        pszOption = "secure path";
1254
0
        break;
1255
0
      case BSCVLC_HDR_OPT_HELLO:
1256
0
        pszOption = "hello";
1257
0
        break;
1258
0
      case BSCVLC_HDR_OPT_IDENTITY:
1259
0
        pszOption = "identity";
1260
0
        break;
1261
0
      case BSCVLC_HDR_OPT_HINT:
1262
0
        pszOption = "hint";
1263
0
        break;
1264
0
      case BSCVLC_HDR_OPT_TOKEN:
1265
0
        pszOption = "token";
1266
0
        break;
1267
0
      case BSCVLC_HDR_OPT_PROPRIETARY:
1268
0
        pszOption = "proprietary";
1269
0
        break;
1270
0
      default:
1271
0
        pszOption = "reserved by ASHREA";
1272
0
        break;
1273
0
      }
1274
1275
0
      subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, start, offset - start,
1276
0
          ett_bscvlc_hdr, NULL, "Data %s option %s", pszUnderstand, pszOption);
1277
0
      proto_tree_add_bitmask_value(subtree, tvb, start, hf_bscvlc_header,
1278
0
        ett_bscvlc_hdr, bscvlc_header_flags, hdr_byte);
1279
1280
0
      if(bDataFlag)
1281
0
      {
1282
0
        proto_tree_add_item(subtree, hf_bscvlc_header_length, tvb, start + 1, 2, ENC_BIG_ENDIAN);
1283
0
        switch(option)
1284
0
        {
1285
0
        case BSCVLC_HDR_OPT_HELLO:
1286
0
          proto_tree_add_bitmask_value(subtree, tvb, start + 3, hf_bscvlc_hello_opt,
1287
0
            ett_bscvlc_hdr, bscvlc_hello1_opt_flags, tvb_get_uint8(tvb, start + 3));
1288
0
          break;
1289
0
        case BSCVLC_HDR_OPT_IDENTITY:
1290
0
          proto_tree_add_item(subtree, hf_bscvlc_identity_device_id, tvb, start + 3, 3, ENC_BIG_ENDIAN);
1291
0
          break;
1292
0
        case BSCVLC_HDR_OPT_HINT:
1293
0
          bacnet_dissect_scope(tvb_new_subset_length(tvb, start, npdu_length + 3), pinfo, subtree, 3, "scope: ");
1294
0
          break;
1295
0
        case BSCVLC_HDR_OPT_TOKEN:
1296
0
          bacnet_dissect_token(tvb_new_subset_length(tvb, start, npdu_length + 3), pinfo, subtree, 3, "token: ");
1297
0
          break;
1298
0
        default:
1299
0
          proto_tree_add_item(subtree, hf_bscvlc_header_data, tvb, start + 3, npdu_length, ENC_NA);
1300
0
          break;
1301
0
        }
1302
0
      }
1303
0
    }
1304
0
  }
1305
1306
0
  switch (bvlc_function)
1307
0
  {
1308
0
  case 0x02: /* Address-Resolution */
1309
0
  case 0x05: /* Advertisement-Solicitation */
1310
0
  case 0x08: /* Disconnect-Request */
1311
0
  case 0x09: /* Disconnect-ACK */
1312
0
  case 0x0A: /* Heartbeat-Request */
1313
0
  case 0x0B: /* Heartbeat-ACK */
1314
0
    break;
1315
0
  case 0x00: /* BVLC-Result */
1316
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1317
0
        ett_bscvlc_hdr, NULL, "%s", "BVLC-Result");
1318
0
    proto_tree_add_item(subtree, hf_bscvlc_function, tvb,
1319
0
        offset, 1, ENC_NA);
1320
0
    offset++;
1321
0
    proto_tree_add_item(subtree, hf_bscvlc_result, tvb,
1322
0
        offset, 1, ENC_NA);
1323
0
    bvlc_result = tvb_get_uint8(tvb, offset);
1324
0
    offset++;
1325
1326
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
1327
0
        val_to_str_const(bvlc_result, bscvlc_result_names, "unknown"));
1328
1329
0
    if(bvlc_result)
1330
0
    {
1331
0
      proto_tree_add_item(subtree, hf_bscvlc_header_marker, tvb,
1332
0
          offset, 1, ENC_NA);
1333
0
      offset++;
1334
0
      proto_tree_add_item(subtree, hf_bscvlc_error_class, tvb,
1335
0
          offset, 2, ENC_BIG_ENDIAN);
1336
0
      offset += 2;
1337
0
      proto_tree_add_item(subtree, hf_bscvlc_error_code, tvb,
1338
0
          offset, 2, ENC_BIG_ENDIAN);
1339
0
      offset += 2;
1340
0
      proto_tree_add_item(subtree, hf_bscvlc_result_data, tvb,
1341
0
          offset, packet_length - offset, ENC_NA);
1342
0
    }
1343
    /* Force and of packet */
1344
0
    offset = packet_length;
1345
0
    break;
1346
0
  case 0x03: /* Address-Resolution-ACK */
1347
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1348
0
        ett_bscvlc_hdr, NULL, "%s", "Address-Resolution-ACK");
1349
0
    proto_tree_add_item(subtree, hf_bscvlc_uris, tvb,
1350
0
        offset, packet_length - offset, ENC_NA);
1351
    /* Force and of packet */
1352
0
    offset = packet_length;
1353
0
    break;
1354
0
  case 0x04: /* Advertisement */
1355
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1356
0
        ett_bscvlc_hdr, NULL, "%s", "Advertisement");
1357
0
    proto_tree_add_item(subtree, hf_bscvlc_hub_conn_state, tvb,
1358
0
        offset, 1, ENC_NA);
1359
0
    offset++;
1360
0
    proto_tree_add_item(subtree, hf_bscvlc_accept_conns, tvb,
1361
0
        offset, 1, ENC_NA);
1362
0
    offset++;
1363
0
    proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1364
0
        offset, 2, ENC_BIG_ENDIAN);
1365
0
    offset += 2;
1366
0
    proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1367
0
        offset, 2, ENC_BIG_ENDIAN);
1368
0
    offset += 2;
1369
0
    break;
1370
0
  case 0x06: /* Connect-Request */
1371
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1372
0
        ett_bscvlc_hdr, NULL, "%s", "Connect-Request");
1373
0
    proto_tree_add_item(subtree, hf_bscvlc_connect_vmac, tvb,
1374
0
        offset, 6, ENC_NA);
1375
0
    offset += 6;
1376
0
    proto_tree_add_item(subtree, hf_bscvlc_connect_uuid, tvb,
1377
0
        offset, 16, ENC_NA);
1378
0
    offset += 16;
1379
0
    proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1380
0
        offset, 2, ENC_BIG_ENDIAN);
1381
0
    offset += 2;
1382
0
    proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1383
0
        offset, 2, ENC_BIG_ENDIAN);
1384
0
    offset += 2;
1385
0
    break;
1386
0
  case 0x07: /* Connect-Accept */
1387
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1388
0
        ett_bscvlc_hdr, NULL, "%s", "Connect-Accept");
1389
0
    proto_tree_add_item(subtree, hf_bscvlc_connect_vmac, tvb,
1390
0
        offset, 6, ENC_NA);
1391
0
    offset += 6;
1392
0
    proto_tree_add_item(subtree, hf_bscvlc_connect_uuid, tvb,
1393
0
        offset, 16, ENC_NA);
1394
0
    offset += 16;
1395
0
    proto_tree_add_item(subtree, hf_bscvlc_max_bvlc_length, tvb,
1396
0
        offset, 2, ENC_BIG_ENDIAN);
1397
0
    offset += 2;
1398
0
    proto_tree_add_item(subtree, hf_bscvlc_max_npdu_length, tvb,
1399
0
        offset, 2, ENC_BIG_ENDIAN);
1400
0
    offset += 2;
1401
0
    break;
1402
0
  case 0x0C: /* Proprietary-Message */
1403
0
    subtree = proto_tree_add_subtree_format(bvlc_tree, tvb, offset, packet_length - offset,
1404
0
        ett_bscvlc_hdr, NULL, "%s", "Proprietary-Message");
1405
0
    proto_tree_add_item(subtree, hf_bscvlc_vendor_id, tvb,
1406
0
        offset, 2, ENC_BIG_ENDIAN);
1407
0
    offset += 2;
1408
0
    proto_tree_add_item(subtree, hf_bscvlc_proprietary_opt_type, tvb,
1409
0
        offset, 1, ENC_NA);
1410
0
    offset++;
1411
0
    proto_tree_add_item(subtree, hf_bscvlc_proprietary_data, tvb,
1412
0
        offset, packet_length - offset, ENC_NA);
1413
    /* Force and of packet */
1414
0
    offset = packet_length;
1415
0
    break;
1416
0
  case 0x01: /* Encapsulated-NPDU */
1417
0
  default:
1418
    /* Here we assume additional payload belongs to upper layers and will be decoded later */
1419
0
    break;
1420
0
  }
1421
1422
  /* Let the remaining frame to be decoded elsewhere */
1423
0
  npdu_length = packet_length - offset;
1424
0
  next_tvb = tvb_new_subset_length(tvb, offset, npdu_length);
1425
  /* Code from Guy Harris */
1426
0
  if (!dissector_try_uint(bscvlc_dissector_table,
1427
0
    bvlc_function, next_tvb, pinfo, tree)) {
1428
    /* Unknown function - dissect the payload as data */
1429
0
    call_data_dissector(next_tvb, pinfo, tree);
1430
0
  }
1431
1432
0
  return tvb_reported_length(tvb);
1433
0
}
1434
1435
void
1436
proto_register_bvlc(void)
1437
15
{
1438
15
  static hf_register_info hf[] = {
1439
15
    { &hf_bvlc_type,
1440
15
      { "Type",           "bvlc.type",
1441
15
      FT_UINT8, BASE_HEX, VALS(bvlc_types), 0,
1442
15
      NULL, HFILL }
1443
15
    },
1444
15
    { &hf_bvlc_function,
1445
15
      { "Function",           "bvlc.function",
1446
15
      FT_UINT8, BASE_HEX, VALS(bvlc_function_names), 0,
1447
15
      "BVLC Function", HFILL }
1448
15
    },
1449
15
    { &hf_bvlc_ipv6_function,
1450
15
      { "Function",           "bvlc.function_ipv6",
1451
15
      FT_UINT8, BASE_HEX, VALS(bvlc_ipv6_function_names), 0,
1452
15
      "BVLC Function IPV6", HFILL }
1453
15
    },
1454
15
    { &hf_bvlc_length,
1455
15
      { "BVLC-Length",        "bvlc.length",
1456
15
      FT_UINT16, BASE_DEC, NULL, 0,
1457
15
      "Length of BVLC", HFILL }
1458
15
    },
1459
15
    { &hf_bvlc_virt_source,
1460
15
      { "BVLC-Virtual-Source", "bvlc.virtual_source",
1461
15
      FT_UINT24, BASE_DEC_HEX, NULL, 0,
1462
15
      "Virtual source address of BVLC", HFILL }
1463
15
    },
1464
15
    { &hf_bvlc_virt_dest,
1465
15
      { "BVLC-Virtual-Destination", "bvlc.virtual_dest",
1466
15
      FT_UINT24, BASE_DEC_HEX, NULL, 0,
1467
15
      "Virtual destination address of BVLC", HFILL }
1468
15
    },
1469
15
    { &hf_bvlc_result_ip4,
1470
15
      { "Result",           "bvlc.result",
1471
15
      FT_UINT16, BASE_HEX, VALS(bvlc_result_names), 0,
1472
15
      "Result Code", HFILL }
1473
15
    },
1474
15
    { &hf_bvlc_result_ip6,
1475
15
      { "Result",           "bvlc.result",
1476
15
      FT_UINT16, BASE_HEX, VALS(bvlc_ipv6_result_names), 0,
1477
15
      "Result Code", HFILL }
1478
15
    },
1479
15
    { &hf_bvlc_bdt_ip,
1480
15
      { "IP",           "bvlc.bdt_ip",
1481
15
      FT_IPv4, BASE_NONE, NULL, 0,
1482
15
      "BDT IP", HFILL }
1483
15
    },
1484
15
    { &hf_bvlc_bdt_port,
1485
15
      { "Port",           "bvlc.bdt_port",
1486
15
      FT_UINT16, BASE_DEC, NULL, 0,
1487
15
      "BDT Port", HFILL }
1488
15
    },
1489
15
    { &hf_bvlc_bdt_mask,
1490
15
      { "Mask",           "bvlc.bdt_mask",
1491
15
      FT_BYTES, BASE_NONE, NULL, 0,
1492
15
      "BDT Broadcast Distribution Mask", HFILL }
1493
15
    },
1494
15
    { &hf_bvlc_reg_ttl,
1495
15
      { "TTL",           "bvlc.reg_ttl",
1496
15
      FT_UINT16, BASE_DEC, NULL, 0,
1497
15
      "Foreign Device Time To Live", HFILL }
1498
15
    },
1499
15
    { &hf_bvlc_fdt_ip,
1500
15
      { "IP",           "bvlc.fdt_ip",
1501
15
      FT_IPv4, BASE_NONE, NULL, 0,
1502
15
      "FDT IP", HFILL }
1503
15
    },
1504
15
    { &hf_bvlc_fdt_ipv6,
1505
15
      { "IP",           "bvlc.fdt_ipv6",
1506
15
      FT_IPv6, BASE_NONE, NULL, 0,
1507
15
      "FDT IP", HFILL }
1508
15
    },
1509
15
    { &hf_bvlc_fdt_port,
1510
15
      { "Port",           "bvlc.fdt_port",
1511
15
      FT_UINT16, BASE_DEC, NULL, 0,
1512
15
      "FDT Port", HFILL }
1513
15
    },
1514
15
    { &hf_bvlc_fdt_ttl,
1515
15
      { "TTL",           "bvlc.fdt_ttl",
1516
15
      FT_UINT16, BASE_DEC, NULL, 0,
1517
15
      "Foreign Device Time To Live", HFILL }
1518
15
    },
1519
15
    { &hf_bvlc_fdt_timeout,
1520
15
      { "Timeout",           "bvlc.fdt_timeout",
1521
15
      FT_UINT16, BASE_DEC, NULL, 0,
1522
15
      "Foreign Device Timeout (seconds)", HFILL }
1523
15
    },
1524
15
    { &hf_bvlc_fwd_ip,
1525
15
      { "IP",           "bvlc.fwd_ip",
1526
15
      FT_IPv4, BASE_NONE, NULL, 0,
1527
15
      "FWD IP", HFILL }
1528
15
    },
1529
15
    { &hf_bvlc_fwd_port,
1530
15
      { "Port",           "bvlc.fwd_port",
1531
15
      FT_UINT16, BASE_DEC, NULL, 0,
1532
15
      "FWD Port", HFILL }
1533
15
    },
1534
15
    { &hf_bvlc_orig_source_addr,
1535
15
      { "IP",             "bvlc.orig_source_addr",
1536
15
      FT_IPv6, BASE_NONE, NULL, 0,
1537
15
      "ORIG IP", HFILL }
1538
15
    },
1539
15
    { &hf_bvlc_orig_source_port,
1540
15
      { "Port",           "bvlc.orig_source_port",
1541
15
      FT_UINT16, BASE_DEC, NULL, 0,
1542
15
      "ORIG Port", HFILL }
1543
15
    },
1544
15
  };
1545
1546
15
  static int *ett[] = {
1547
15
    &ett_bvlc,
1548
15
    &ett_bdt,
1549
15
    &ett_fdt,
1550
15
  };
1551
1552
15
  static hf_register_info bsc_hf[] = {
1553
15
    { &hf_bscvlc_control,
1554
15
      { "Control",    "bscvlc.control",
1555
15
      FT_UINT8, BASE_HEX, NULL, 0,
1556
15
      "BSCVLC Control", HFILL }
1557
15
    },
1558
15
    { &hf_bscvlc_control_data_option,
1559
15
      { "Data Option",  "bscvlc.control_data_option",
1560
15
      FT_BOOLEAN, 8, TFS(&control_data_option_set_high),
1561
15
      BSCVLC_CONTROL_DATA_OPTION, "BSCVLC Control", HFILL }
1562
15
    },
1563
15
    { &hf_bscvlc_control_destination_option,
1564
15
      { "Destination Option", "bscvlc.control_dest_option",
1565
15
      FT_BOOLEAN, 8, TFS(&control_destination_option_set_high),
1566
15
      BSCVLC_CONTROL_DEST_OPTION, "BSCVLC Control", HFILL }
1567
15
    },
1568
15
    { &hf_bscvlc_control_destination_address,
1569
15
      { "Destination Address","bscvlc.control_dest_address",
1570
15
      FT_BOOLEAN, 8, TFS(&control_destination_address_set_high),
1571
15
      BSCVLC_CONTROL_DEST_ADDRESS, "BSCVLC Control", HFILL }
1572
15
    },
1573
15
    { &hf_bscvlc_control_origin_address,
1574
15
      { "Origin Address", "bscvlc.control_orig_address",
1575
15
      FT_BOOLEAN, 8, TFS(&control_orig_address_set_high),
1576
15
      BSCVLC_CONTROL_ORIG_ADDRESS, "BSCVLC Control", HFILL }
1577
15
    },
1578
15
    { &hf_bscvlc_control_reserved,
1579
15
      { "Reserved", "bscvlc.control_reserved",
1580
15
      FT_BOOLEAN, 8, TFS(&control_reserved_set_high),
1581
15
      BSCVLC_CONTROL_RESERVED, "BSCVLC Control", HFILL }
1582
15
    },
1583
15
    { &hf_bscvlc_header,
1584
15
      { "Header Data Length", "bscvlc.header",
1585
15
      FT_UINT8, BASE_HEX, NULL, 0,
1586
15
      "BSCVLC Header Control Data", HFILL }
1587
15
    },
1588
15
    { &hf_bscvlc_header_marker,
1589
15
      { "Header Error Marker","bscvlc.header_error_marker",
1590
15
      FT_UINT8, BASE_HEX, NULL, 0,
1591
15
      "BSCVLC Header Error Marker", HFILL }
1592
15
    },
1593
15
    { &hf_bscvlc_header_length,
1594
15
      { "Header Data Length", "bscvlc.header_length",
1595
15
      FT_UINT16, BASE_DEC, NULL, 0,
1596
15
      "BSCVLC Header Data Length", HFILL }
1597
15
    },
1598
15
    { &hf_bscvlc_header_data,
1599
15
      { "Header Data",  "bscvlc.header_data",
1600
15
      FT_BYTES, BASE_NONE, NULL, 0,
1601
15
      "BSCVLC Header Option", HFILL }
1602
15
    },
1603
15
    { &hf_bscvlc_header_opt_type,
1604
15
      { "Header Type",  "bscvlc.header_type",
1605
15
      FT_UINT8, BASE_HEX, VALS(bscvlc_header_type_names),
1606
15
      BSCVLC_HDR_OPTION_TYPE_MASK, "BSCVLC Header Option", HFILL }
1607
15
    },
1608
15
    { &hf_bscvlc_header_opt_data,
1609
15
      { "Header Data",  "bscvlc.header_data_present",
1610
15
      FT_BOOLEAN, 8, TFS(&header_opt_data_set_high),
1611
15
      BSCVLC_HDR_DATA_PRESENT, "BSCVLC Header Option", HFILL }
1612
15
    },
1613
15
    { &hf_bscvlc_header_opt_must_understand,
1614
15
      { "Header Must Understand","bscvlc.header_understand",
1615
15
      FT_BOOLEAN, 8, TFS(&header_opt_must_understand_set_high),
1616
15
      BSCVLC_HDR_MUST_UNDERSTAND, "BSCVLC Header Option", HFILL }
1617
15
    },
1618
15
    { &hf_bscvlc_header_opt_more,
1619
15
      { "Header More",  "bscvlc.header_more",
1620
15
      FT_BOOLEAN, 8, TFS(&header_opt_more_set_high),
1621
15
      BSCVLC_HDR_MORE_OPTIONS_FOLLOW, "BSCVLC Header Option", HFILL }
1622
15
    },
1623
15
    { &hf_bscvlc_vendor_id,
1624
15
      { "Vendor ID",          "bscvlc.vendor_id",
1625
15
      FT_UINT16, BASE_HEX, NULL, 0,
1626
15
      "BSCVLC Vendor ID", HFILL }
1627
15
    },
1628
15
    { &hf_bscvlc_proprietary_opt_type,
1629
15
      { "Proprietary Type", "bscvlc.proprietary_type",
1630
15
      FT_UINT8, BASE_HEX, NULL, 0,
1631
15
      "BSCVLC Proprietary Type", HFILL }
1632
15
    },
1633
15
    { &hf_bscvlc_proprietary_data,
1634
15
      { "Proprietary Data", "bscvlc.proprietary_data",
1635
15
      FT_BYTES, BASE_NONE, NULL, 0,
1636
15
      "BSCVLC Proprietary Data", HFILL }
1637
15
    },
1638
15
    { &hf_bscvlc_hub_conn_state,
1639
15
      { "Hub Connection Status","bscvlc.hub_conn_state",
1640
15
      FT_UINT8, BASE_HEX, VALS(bscvlc_hub_conn_state_names), 0,
1641
15
      "BSCVLC Hub Connection Status", HFILL }
1642
15
    },
1643
15
    { &hf_bscvlc_accept_conns,
1644
15
      { "Hub Accepts Connections","bscvlc.accept_conns",
1645
15
      FT_UINT8, BASE_HEX, VALS(bscvlc_hub_accept_conns_names), 0,
1646
15
      "BSCVLC Accepts Connections", HFILL }
1647
15
    },
1648
15
    { &hf_bscvlc_max_bvlc_length,
1649
15
      { "Max. BVLC Length", "bscvlc.max_bvlc_length",
1650
15
      FT_UINT16, BASE_DEC, NULL, 0,
1651
15
      "Max Supported BVLC Length", HFILL }
1652
15
    },
1653
15
    { &hf_bscvlc_max_npdu_length,
1654
15
      { "Max. NPDU Length", "bscvlc.max_npdu_length",
1655
15
      FT_UINT16, BASE_DEC, NULL, 0,
1656
15
      "Max Supported NPDU Length", HFILL }
1657
15
    },
1658
15
    { &hf_bscvlc_function,
1659
15
      { "Function",           "bscvlc.function",
1660
15
      FT_UINT8, BASE_HEX, VALS(bscvlc_function_names), 0,
1661
15
      "BSCVLC Function", HFILL }
1662
15
    },
1663
15
    { &hf_bscvlc_result,
1664
15
      { "Result",             "bscvlc.result",
1665
15
      FT_UINT8, BASE_HEX, VALS(bscvlc_result_names), 0,
1666
15
      "Result Code", HFILL }
1667
15
    },
1668
15
    { &hf_bscvlc_error_class,
1669
15
      { "Error Class",  "bscvlc.error_class",
1670
15
      FT_UINT32, BASE_DEC, VALS(BACnetErrorClass), 0, NULL, HFILL }
1671
15
    },
1672
15
    { &hf_bscvlc_error_code,
1673
15
      { "Error Code",   "bscvlc.error_code",
1674
15
      FT_UINT32, BASE_DEC|BASE_EXT_STRING, &BACnetErrorCode_ext, 0, NULL, HFILL }
1675
15
    },
1676
15
    { &hf_bscvlc_result_data,
1677
15
      { "Result Data",  "bscvlc.result_data",
1678
15
      FT_BYTES, BASE_NONE, NULL, 0,
1679
15
      "BSCVLC Result Data", HFILL }
1680
15
    },
1681
15
    { &hf_bscvlc_uris,
1682
15
      { "URI's",    "bscvlc.uris",
1683
15
      FT_BYTES, BASE_NONE, NULL, 0,
1684
15
      "BSCVLC Address URI's", HFILL }
1685
15
    },
1686
15
    { &hf_bscvlc_msg_id,
1687
15
      { "Message ID",         "bscvlc.msgid",
1688
15
      FT_UINT16, BASE_DEC, NULL, 0,
1689
15
      "BSCVLC Message ID", HFILL }
1690
15
    },
1691
15
    { &hf_bscvlc_orig_vmac,
1692
15
      { "SVMAC",              "bscvlc.orig_virtual_address",
1693
15
      FT_BYTES, BASE_NONE, NULL, 0,
1694
15
      "ORIG VMAC", HFILL }
1695
15
    },
1696
15
    { &hf_bscvlc_dest_vmac,
1697
15
      { "DVMAC",              "bscvlc.dest_virtual_address",
1698
15
      FT_BYTES, BASE_NONE, NULL, 0,
1699
15
      "DEST VMAC", HFILL }
1700
15
    },
1701
15
    { &hf_bscvlc_connect_vmac,
1702
15
      { "Connecting VMAC",  "bscvlc.connect_virtual_address",
1703
15
      FT_BYTES, BASE_NONE, NULL, 0,
1704
15
      "BSCVLC Connecting VMAC", HFILL }
1705
15
    },
1706
15
    { &hf_bscvlc_connect_uuid,
1707
15
      { "Connecting UUID",  "bscvlc.connect_uuid",
1708
15
      FT_BYTES, BASE_NONE, NULL, 0,
1709
15
      "BSCVLC Connecting UUID", HFILL }
1710
15
    },
1711
15
    { &hf_bscvlc_identity_device_id,
1712
15
      { "Identity Device ID", "bscvlc.identity_device_id",
1713
15
      FT_UINT24, BASE_DEC, NULL, 0,
1714
15
      "BSCVLC Identity Device ID", HFILL }
1715
15
    },
1716
15
    { &hf_bscvlc_hello_opt,
1717
15
      { "Hello option",   "bscvlc.hello_opt",
1718
15
      FT_UINT8, BASE_HEX, NULL, 0,
1719
15
      "BSCVLC Hello option", HFILL }
1720
15
    },
1721
15
    { &hf_bscvlc_hello_opt_identity_relay,
1722
15
      { "Hello Identity Relay","bscvlc.hello_opt_identity_relay",
1723
15
      FT_BOOLEAN, 8, TFS(&hello_opt_identity_relay_set_high),
1724
15
      BSCVLC_HELLO_IDENTITY_RELAY, "BSCVLC Hello Option", HFILL }
1725
15
    },
1726
15
  };
1727
1728
15
  static int *bsc_ett[] = {
1729
15
    &ett_bscvlc,
1730
15
    &ett_bscvlc_ctrl,
1731
15
    &ett_bscvlc_hdr
1732
15
  };
1733
1734
15
  proto_bvlc = proto_register_protocol("BACnet Virtual Link Control", "BVLC", "bvlc");
1735
1736
15
  proto_register_field_array(proto_bvlc, hf, array_length(hf));
1737
15
  proto_register_subtree_array(ett, array_length(ett));
1738
1739
15
  bvlc_handle = register_dissector("bvlc", dissect_bvlc, proto_bvlc);
1740
1741
15
  bvlc_dissector_table = register_dissector_table("bvlc.function", "BVLC Function", proto_bvlc, FT_UINT8, BASE_HEX);
1742
15
  bvlc_ipv6_dissector_table = register_dissector_table("bvlc.function_ipv6", "BVLC Function IPV6", proto_bvlc, FT_UINT8, BASE_HEX);
1743
1744
15
  proto_bscvlc = proto_register_protocol("BACnet Secure Connect Virtual Link Control", "BSCVLC", "bscvlc");
1745
1746
15
  proto_register_field_array(proto_bscvlc, bsc_hf, array_length(bsc_hf));
1747
15
  proto_register_subtree_array(bsc_ett, array_length(bsc_ett));
1748
1749
15
  bscvlc_handle = register_dissector("bscvlc", dissect_bscvlc, proto_bscvlc);
1750
1751
15
  bscvlc_dissector_table = register_dissector_table("bscvlc.function", "BSCVLC Function", proto_bscvlc, FT_UINT8, BASE_HEX);
1752
15
}
1753
1754
void
1755
proto_reg_handoff_bvlc(void)
1756
15
{
1757
15
  dissector_add_uint_with_preference("udp.port", BVLC_UDP_PORT, bvlc_handle);
1758
15
  dissector_add_string("ws.protocol", "hub.bsc.bacnet.org", bscvlc_handle);
1759
15
  dissector_add_string("ws.protocol", "dc.bsc.bacnet.org", bscvlc_handle);
1760
15
}
1761
1762
/*
1763
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1764
 *
1765
 * Local variables:
1766
 * c-basic-offset: 8
1767
 * tab-width: 8
1768
 * indent-tabs-mode: t
1769
 * End:
1770
 *
1771
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1772
 * :indentSize=8:tabSize=8:noTabs=false:
1773
 */