2 * Routines for VRT (VITA 49) packet disassembly
3 * Copyright 2012 Ettus Research LLC - Nick Foster <nick@ettus.com>: original dissector
4 * Copyright 2013 Alexander Chemeris <alexander.chemeris@gmail.com>: dissector improvement
5 * Copyright 2013 Dario Lombardo (lomato@gmail.com): Official Wireshark port
7 * Original dissector repository: https://github.com/bistromath/vrt-dissector
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32 #include <epan/packet.h>
33 #include <epan/prefs.h>
35 static gint dissector_port_pref
= 4991;
37 static int proto_vrt
= -1;
40 static int hf_vrt_header
= -1; /* 32-bit header */
41 static int hf_vrt_type
= -1; /* 4-bit pkt type */
42 static int hf_vrt_cidflag
= -1; /* 1-bit class ID flag */
43 static int hf_vrt_tflag
= -1; /* 1-bit trailer flag */
44 static int hf_vrt_tsmflag
= -1; /* 1-bit timestamp mode */
45 static int hf_vrt_tsi
= -1; /* 2-bit timestamp type */
46 static int hf_vrt_tsf
= -1; /* 2-bit fractional timestamp type */
47 static int hf_vrt_seq
= -1; /* 4-bit sequence number */
48 static int hf_vrt_len
= -1; /* 16-bit length */
49 static int hf_vrt_sid
= -1; /* 32-bit stream ID (opt.) */
50 static int hf_vrt_cid
= -1; /* 64-bit class ID (opt.) */
51 static int hf_vrt_cid_oui
= -1; /* 24-bit class ID OUI */
52 static int hf_vrt_cid_icc
= -1; /* 16-bit class ID ICC */
53 static int hf_vrt_cid_pcc
= -1; /* 16-bit class ID PCC */
54 static int hf_vrt_ts_int
= -1; /* 32-bit integer timestamp (opt.) */
55 static int hf_vrt_ts_frac_picosecond
= -1; /* 64-bit fractional timestamp (opt.) */
56 static int hf_vrt_ts_frac_sample
= -1; /* 64-bit fractional timestamp (opt.) */
57 static int hf_vrt_data
= -1; /* data */
58 static int hf_vrt_trailer
= -1; /* 32-bit trailer (opt.) */
59 static int hf_vrt_trailer_enables
= -1; /* trailer indicator enables */
60 static int hf_vrt_trailer_ind
= -1; /* trailer indicators */
61 static int hf_vrt_trailer_e
= -1; /* ass con pac cnt enable */
62 static int hf_vrt_trailer_acpc
= -1; /* associated context packet count */
63 static int hf_vrt_trailer_en_caltime
= -1; /* calibrated time indicator */
64 static int hf_vrt_trailer_en_valid
= -1; /* valid data ind */
65 static int hf_vrt_trailer_en_reflock
= -1; /* reference locked ind */
66 static int hf_vrt_trailer_en_agc
= -1; /* AGC/MGC enabled ind */
67 static int hf_vrt_trailer_en_sig
= -1; /* signal detected ind */
68 static int hf_vrt_trailer_en_inv
= -1; /* spectral inversion ind */
69 static int hf_vrt_trailer_en_overrng
= -1; /* overrange indicator */
70 static int hf_vrt_trailer_en_sampleloss
= -1; /* sample loss indicator */
71 static int hf_vrt_trailer_en_user0
= -1; /* User indicator 0 */
72 static int hf_vrt_trailer_en_user1
= -1; /* User indicator 1 */
73 static int hf_vrt_trailer_en_user2
= -1; /* User indicator 2 */
74 static int hf_vrt_trailer_en_user3
= -1; /* User indicator 3 */
75 static int hf_vrt_trailer_ind_caltime
= -1; /* calibrated time indicator */
76 static int hf_vrt_trailer_ind_valid
= -1; /* valid data ind */
77 static int hf_vrt_trailer_ind_reflock
= -1; /* reference locked ind */
78 static int hf_vrt_trailer_ind_agc
= -1; /* AGC/MGC enabled ind */
79 static int hf_vrt_trailer_ind_sig
= -1; /* signal detected ind */
80 static int hf_vrt_trailer_ind_inv
= -1; /* spectral inversion ind */
81 static int hf_vrt_trailer_ind_overrng
= -1; /* overrange indicator */
82 static int hf_vrt_trailer_ind_sampleloss
= -1; /* sample loss indicator */
83 static int hf_vrt_trailer_ind_user0
= -1; /* User indicator 0 */
84 static int hf_vrt_trailer_ind_user1
= -1; /* User indicator 1 */
85 static int hf_vrt_trailer_ind_user2
= -1; /* User indicator 2 */
86 static int hf_vrt_trailer_ind_user3
= -1; /* User indicator 3 */
88 /* subtree state variables */
89 static gint ett_vrt
= -1;
90 static gint ett_header
= -1;
91 static gint ett_trailer
= -1;
92 static gint ett_indicators
= -1;
93 static gint ett_ind_enables
= -1;
94 static gint ett_cid
= -1;
96 static const value_string packet_types
[] = {
97 {0x00, "IF data packet without stream ID"},
98 {0x01, "IF data packet with stream ID"},
99 {0x02, "Extension data packet without stream ID"},
100 {0x03, "Extension data packet with stream ID"},
101 {0x04, "IF context packet"},
102 {0x05, "Extension context packet"},
106 static const value_string tsi_types
[] = {
107 {0x00, "No integer-seconds timestamp field included"},
108 {0x01, "Coordinated Universal Time (UTC)"},
114 static const value_string tsf_types
[] = {
115 {0x00, "No fractional-seconds timestamp field included"},
116 {0x01, "Sample count timestamp"},
117 {0x02, "Real time (picoseconds) timestamp"},
118 {0x03, "Free running count timestamp"},
122 static const value_string tsm_types
[] = {
123 {0x00, "Precise timestamp resolution"},
124 {0x01, "General timestamp resolution"},
128 static const int *enable_hfs
[] = {
129 &hf_vrt_trailer_en_user3
,
130 &hf_vrt_trailer_en_user2
,
131 &hf_vrt_trailer_en_user1
,
132 &hf_vrt_trailer_en_user0
,
133 &hf_vrt_trailer_en_sampleloss
,
134 &hf_vrt_trailer_en_overrng
,
135 &hf_vrt_trailer_en_inv
,
136 &hf_vrt_trailer_en_sig
,
137 &hf_vrt_trailer_en_agc
,
138 &hf_vrt_trailer_en_reflock
,
139 &hf_vrt_trailer_en_valid
,
140 &hf_vrt_trailer_en_caltime
143 static const int *ind_hfs
[] = {
144 &hf_vrt_trailer_ind_user3
,
145 &hf_vrt_trailer_ind_user2
,
146 &hf_vrt_trailer_ind_user1
,
147 &hf_vrt_trailer_ind_user0
,
148 &hf_vrt_trailer_ind_sampleloss
,
149 &hf_vrt_trailer_ind_overrng
,
150 &hf_vrt_trailer_ind_inv
,
151 &hf_vrt_trailer_ind_sig
,
152 &hf_vrt_trailer_ind_agc
,
153 &hf_vrt_trailer_ind_reflock
,
154 &hf_vrt_trailer_ind_valid
,
155 &hf_vrt_trailer_ind_caltime
158 void dissect_header(tvbuff_t
*tvb
, proto_tree
*tree
, int type
, int offset
);
159 void dissect_trailer(tvbuff_t
*tvb
, proto_tree
*tree
, int offset
);
160 void dissect_cid(tvbuff_t
*tvb
, proto_tree
*tree
, int offset
);
161 void proto_reg_handoff_vrt(void);
163 static void dissect_vrt(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
175 proto_tree
*vrt_tree
;
178 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "VITA 49");
179 col_clear(pinfo
->cinfo
,COL_INFO
);
181 /* HACK to support UHD's weird header offset on data packets. */
182 if (tvb_get_guint8(tvb
, 0) == 0) offset
+= 4;
184 /* get packet type */
185 type
= tvb_get_guint8(tvb
, offset
) >> 4;
186 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(type
, packet_types
, "Reserved packet type (0x%02x)"));
188 /* get SID, CID, T, TSI, and TSF flags */
189 sidflag
= (type
& 1) || (type
== 4);
190 cidflag
= (tvb_get_guint8(tvb
, offset
) >> 3) & 0x01;
191 /* tflag is in data packets but not context packets */
192 tflag
= (tvb_get_guint8(tvb
, offset
) >> 2) & 0x01;
193 if(type
== 4) tflag
= 0; /* this should be unnecessary but we do it
195 /* tsmflag is in context packets but not data packets
196 tsmflag = (tvb_get_guint8(tvb, offset) >> 0) & 0x01; */
197 tsiflag
= (tvb_get_guint8(tvb
, offset
+1) >> 6) & 0x03;
198 tsfflag
= (tvb_get_guint8(tvb
, offset
+1) >> 4) & 0x03;
199 len
= tvb_get_ntohs(tvb
, offset
+2);
200 nsamps
= len
- 1 - sidflag
- cidflag
*2 - tsiflag
- tsfflag
*2 - tflag
;
202 if (tree
) { /* we're being asked for details */
203 ti
= proto_tree_add_item(tree
, proto_vrt
, tvb
, offset
, -1, ENC_NA
);
204 vrt_tree
= proto_item_add_subtree(ti
, ett_vrt
);
206 dissect_header(tvb
, vrt_tree
, type
, offset
);
209 /* header's done! if SID (last bit of type), put the stream ID here */
211 proto_tree_add_item(vrt_tree
, hf_vrt_sid
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
215 /* if there's a class ID (cidflag), put the class ID here */
217 dissect_cid(tvb
, vrt_tree
, offset
);
221 /* if TSI and/or TSF, populate those here */
223 proto_tree_add_item(vrt_tree
, hf_vrt_ts_int
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
227 if(tsfflag
== 1 || tsfflag
== 3) {
228 proto_tree_add_item(vrt_tree
, hf_vrt_ts_frac_sample
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
229 } else if(tsfflag
== 2) {
230 proto_tree_add_item(vrt_tree
, hf_vrt_ts_frac_picosecond
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
235 /* now we've got either a context packet or a data packet
236 TODO: parse context packet fully instead of just spewing data */
238 /* we're into the data */
241 proto_tree_add_item(vrt_tree
, hf_vrt_data
, tvb
, offset
, nsamps
*4, ENC_NA
);
247 dissect_trailer(tvb
, vrt_tree
, offset
);
251 } else { /* we're being asked for a summary */
256 void dissect_header(tvbuff_t
*tvb
, proto_tree
*tree
, int type
, int _offset
)
259 proto_item
*hdr_item
;
260 proto_tree
*hdr_tree
;
264 hdr_item
= proto_tree_add_item(tree
, hf_vrt_header
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
266 hdr_tree
= proto_item_add_subtree(hdr_item
, ett_header
);
267 proto_tree_add_item(hdr_tree
, hf_vrt_type
, tvb
, offset
, 1, ENC_NA
);
268 proto_tree_add_bits_item(hdr_tree
, hf_vrt_cidflag
, tvb
, (offset
* 8) + 5, 1, ENC_NA
);
270 proto_tree_add_item(hdr_tree
, hf_vrt_tsmflag
, tvb
, offset
, 1, ENC_NA
);
272 proto_tree_add_bits_item(hdr_tree
, hf_vrt_tflag
, tvb
, (offset
* 8) + 6, 1, ENC_NA
);
275 proto_tree_add_item(hdr_tree
, hf_vrt_tsi
, tvb
, offset
, 1, ENC_NA
);
276 proto_tree_add_item(hdr_tree
, hf_vrt_tsf
, tvb
, offset
, 1, ENC_NA
);
277 proto_tree_add_item(hdr_tree
, hf_vrt_seq
, tvb
, offset
, 1, ENC_NA
);
279 proto_tree_add_item(hdr_tree
, hf_vrt_len
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
282 void dissect_trailer(tvbuff_t
*tvb
, proto_tree
*tree
, int offset
)
284 proto_item
*enable_item
, *ind_item
, *trailer_item
;
285 proto_tree
*enable_tree
;
286 proto_tree
*ind_tree
;
287 proto_tree
*trailer_tree
;
291 trailer_item
= proto_tree_add_item(tree
, hf_vrt_trailer
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
292 trailer_tree
= proto_item_add_subtree(trailer_item
, ett_trailer
);
294 /* grab the indicator enables and the indicators
295 only display enables, indicators which are enabled */
296 enable_item
= proto_tree_add_item(trailer_tree
, hf_vrt_trailer_enables
, tvb
, offset
, 2, ENC_NA
);
297 ind_item
= proto_tree_add_item(trailer_tree
, hf_vrt_trailer_ind
, tvb
, offset
+ 1, 2, ENC_NA
);
298 /* grab enable bits */
299 en_bits
= (tvb_get_ntohs(tvb
, offset
) & 0xFFF0) >> 4;
301 /* if there's any enables, start trees for enable bits and for indicators
302 only enables and indicators which are enabled get printed. */
304 enable_tree
= proto_item_add_subtree(enable_item
, ett_ind_enables
);
305 ind_tree
= proto_item_add_subtree(ind_item
, ett_indicators
);
306 for(i
= 11; i
>= 0; i
--) {
307 if(en_bits
& (1<<i
)) {
308 proto_tree_add_bits_item(enable_tree
, *enable_hfs
[i
], tvb
, (offset
+(i
<3)) * 8 + (i
+1), 1, ENC_NA
);
309 proto_tree_add_bits_item(ind_tree
, *ind_hfs
[i
], tvb
, (offset
+(i
<8)+1) * 8 + (i
+5), 1, ENC_NA
);
314 proto_tree_add_bits_item(trailer_tree
, hf_vrt_trailer_e
, tvb
, offset
* 8, 1, ENC_NA
);
315 proto_tree_add_item(trailer_tree
, hf_vrt_trailer_acpc
, tvb
, offset
, 1, ENC_NA
);
318 void dissect_cid(tvbuff_t
*tvb
, proto_tree
*tree
, int offset
)
320 proto_item
*cid_item
;
321 proto_tree
*cid_tree
;
323 cid_item
= proto_tree_add_item(tree
, hf_vrt_cid
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
324 cid_tree
= proto_item_add_subtree(cid_item
, ett_cid
);
327 proto_tree_add_item(cid_tree
, hf_vrt_cid_oui
, tvb
, offset
, 3, ENC_BIG_ENDIAN
);
329 proto_tree_add_item(cid_tree
, hf_vrt_cid_icc
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
331 proto_tree_add_item(cid_tree
, hf_vrt_cid_pcc
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
335 proto_register_vrt(void)
337 static hf_register_info hf
[] = {
339 { "VRT header", "vrt.hdr",
345 { "Packet type", "vrt.type",
347 VALS(packet_types
), 0xF0,
351 { "Class ID included", "vrt.cidflag",
352 FT_BOOLEAN
, BASE_NONE
,
357 { "Trailer included", "vrt.tflag",
358 FT_BOOLEAN
, BASE_NONE
,
363 { "Timestamp mode", "vrt.tsmflag",
365 VALS(tsm_types
), 0x01,
369 { "Integer timestamp type", "vrt.tsi",
371 VALS(tsi_types
), 0xC0,
375 { "Fractional timestamp type", "vrt.tsf",
377 VALS(tsf_types
), 0x30,
381 { "Sequence number", "vrt.seq",
387 { "Length", "vrt.len",
393 { "Integer timestamp", "vrt.ts_int",
398 { &hf_vrt_ts_frac_sample
,
399 { "Fractional timestamp (samples)", "vrt.ts_frac_sample",
404 { &hf_vrt_ts_frac_picosecond
,
405 { "Fractional timestamp (picoseconds)", "vrt.ts_frac_picosecond",
406 FT_DOUBLE
, BASE_NONE
,
411 { "Stream ID", "vrt.sid",
417 { "Class ID", "vrt.cid",
423 { "Data", "vrt.data",
429 { "Trailer", "vrt.trailer",
434 { &hf_vrt_trailer_enables
,
435 { "Indicator enable bits", "vrt.enables",
440 { &hf_vrt_trailer_ind
,
441 { "Indicator bits", "vrt.indicators",
447 { "Associated context packet count enabled", "vrt.e",
448 FT_BOOLEAN
, BASE_NONE
,
452 { &hf_vrt_trailer_acpc
,
453 { "Associated context packet count", "vrt.acpc",
458 { &hf_vrt_trailer_ind_caltime
,
459 { "Calibrated time indicator", "vrt.caltime",
460 FT_BOOLEAN
, BASE_NONE
,
464 { &hf_vrt_trailer_ind_valid
,
465 { "Valid signal indicator", "vrt.valid",
466 FT_BOOLEAN
, BASE_NONE
,
470 { &hf_vrt_trailer_ind_reflock
,
471 { "Reference lock indicator", "vrt.reflock",
472 FT_BOOLEAN
, BASE_NONE
,
476 { &hf_vrt_trailer_ind_agc
,
477 { "AGC/MGC indicator", "vrt.agc",
478 FT_BOOLEAN
, BASE_NONE
,
482 { &hf_vrt_trailer_ind_sig
,
483 { "Signal detected indicator", "vrt.sig",
484 FT_BOOLEAN
, BASE_NONE
,
488 { &hf_vrt_trailer_ind_inv
,
489 { "Spectral inversion indicator", "vrt.inv",
490 FT_BOOLEAN
, BASE_NONE
,
494 { &hf_vrt_trailer_ind_overrng
,
495 { "Overrange indicator", "vrt.overrng",
496 FT_BOOLEAN
, BASE_NONE
,
500 { &hf_vrt_trailer_ind_sampleloss
,
501 { "Lost sample indicator", "vrt.sampleloss",
502 FT_BOOLEAN
, BASE_NONE
,
506 { &hf_vrt_trailer_ind_user0
,
507 { "User indicator 0", "vrt.user0",
508 FT_BOOLEAN
, BASE_NONE
,
512 { &hf_vrt_trailer_ind_user1
,
513 { "User indicator 1", "vrt.user1",
514 FT_BOOLEAN
, BASE_NONE
,
518 { &hf_vrt_trailer_ind_user2
,
519 { "User indicator 2", "vrt.user2",
520 FT_BOOLEAN
, BASE_NONE
,
524 { &hf_vrt_trailer_ind_user3
,
525 { "User indicator 3", "vrt.user3",
526 FT_BOOLEAN
, BASE_NONE
,
530 { &hf_vrt_trailer_en_caltime
,
531 { "Calibrated time indicator enable", "vrt.caltime_en",
532 FT_BOOLEAN
, BASE_NONE
,
536 { &hf_vrt_trailer_en_valid
,
537 { "Valid signal indicator enable", "vrt.valid_en",
538 FT_BOOLEAN
, BASE_NONE
,
542 { &hf_vrt_trailer_en_reflock
,
543 { "Reference lock indicator enable", "vrt.reflock_en",
544 FT_BOOLEAN
, BASE_NONE
,
548 { &hf_vrt_trailer_en_agc
,
549 { "AGC/MGC indicator enable", "vrt.agc_en",
550 FT_BOOLEAN
, BASE_NONE
,
554 { &hf_vrt_trailer_en_sig
,
555 { "Signal detected indicator enable", "vrt.sig_en",
556 FT_BOOLEAN
, BASE_NONE
,
560 { &hf_vrt_trailer_en_inv
,
561 { "Spectral inversion indicator enable", "vrt.inv_en",
562 FT_BOOLEAN
, BASE_NONE
,
566 { &hf_vrt_trailer_en_overrng
,
567 { "Overrange indicator enable", "vrt.overrng_en",
568 FT_BOOLEAN
, BASE_NONE
,
572 { &hf_vrt_trailer_en_sampleloss
,
573 { "Lost sample indicator enable", "vrt.sampleloss_en",
574 FT_BOOLEAN
, BASE_NONE
,
578 { &hf_vrt_trailer_en_user0
,
579 { "User indicator 0 enable", "vrt.user0_en",
580 FT_BOOLEAN
, BASE_NONE
,
584 { &hf_vrt_trailer_en_user1
,
585 { "User indicator 1 enable", "vrt.user1_en",
586 FT_BOOLEAN
, BASE_NONE
,
590 { &hf_vrt_trailer_en_user2
,
591 { "User indicator 2 enable", "vrt.user2_en",
592 FT_BOOLEAN
, BASE_NONE
,
596 { &hf_vrt_trailer_en_user3
,
597 { "User indicator 3 enable", "vrt.user3_en",
598 FT_BOOLEAN
, BASE_NONE
,
603 { "Class ID Organizationally Unique ID", "vrt.oui",
609 { "Class ID Information Class Code", "vrt.icc",
615 { "Class ID Packet Class Code", "vrt.pcc",
622 static gint
*ett
[] = {
631 module_t
*vrt_module
;
633 proto_vrt
= proto_register_protocol (
634 "VITA 49 radio transport protocol", /* name */
635 "VITA 49", /* short name */
639 proto_register_field_array(proto_vrt
, hf
, array_length(hf
));
640 proto_register_subtree_array(ett
, array_length(ett
));
642 vrt_module
= prefs_register_protocol(proto_vrt
, proto_reg_handoff_vrt
);
643 prefs_register_uint_preference(vrt_module
,
645 "Dissector UDP port",
646 "The UDP port used by this dissector",
647 10, &dissector_port_pref
);
651 proto_reg_handoff_vrt(void)
653 static gboolean vrt_prefs_initialized
= FALSE
;
654 static dissector_handle_t vrt_handle
;
655 static gint dissector_port
;
657 if (!vrt_prefs_initialized
) {
658 vrt_handle
= create_dissector_handle(dissect_vrt
, proto_vrt
);
659 vrt_prefs_initialized
= TRUE
;
661 dissector_delete_uint("udp.port", dissector_port
, vrt_handle
);
664 dissector_port
= dissector_port_pref
;
666 dissector_add_uint("udp.port", dissector_port
, vrt_handle
);
670 * Editor modelines - http://www.wireshark.org/tools/modelines.html
675 * indent-tabs-mode: nil
678 * vi: set shiftwidth=4 tabstop=8 expandtab:
679 * :indentSize=4:tabSize=8:noTabs=true: