2 * Reliable Multicast Transport (RMT)
3 * LCT Building Block dissector
4 * Copyright 2005, Stefano Pettini <spettini@users.sourceforge.net>
6 * Layered Coding Transport (LCT):
7 * -------------------------------
9 * Provides transport level support for reliable content delivery
10 * and stream delivery protocols. LCT is specifically designed to
11 * support protocols using IP multicast, but also provides support
12 * to protocols that use unicast. LCT is compatible with congestion
13 * control that provides multiple rate delivery to receivers and
14 * is also compatible with coding techniques that provide
15 * reliable delivery of content.
18 * RFC 3451, Layered Coding Transport (LCT) Building Block
22 * Wireshark - Network traffic analyzer
23 * By Gerald Combs <gerald@wireshark.org>
24 * Copyright 1998 Gerald Combs
26 * This program is free software; you can redistribute it and/or
27 * modify it under the terms of the GNU General Public License
28 * as published by the Free Software Foundation; either version 2
29 * of the License, or (at your option) any later version.
31 * This program is distributed in the hope that it will be useful,
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public License
37 * along with this program; if not, write to the Free Software
38 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
45 #include <epan/packet.h>
46 #include <epan/params.h>
47 #include <epan/strutil.h>
51 #include "packet-rmt-common.h"
53 #define LCT_SCT_FLAG 0x0008
54 #define LCT_ERT_FLAG 0x0004
55 #define LCT_CLOSE_SESSION_FLAG 0x0002
56 #define LCT_CLOSE_OBJECT_FLAG 0x0001
58 void proto_register_rmt_lct(void);
60 static int proto_rmt_lct = -1;
62 static int hf_version = -1;
63 static int hf_fsize_header = -1;
64 static int hf_fsize_cci = -1;
65 static int hf_fsize_tsi = -1;
66 static int hf_fsize_toi = -1;
67 static int hf_flags_header = -1;
68 static int hf_flags_sct_present = -1;
69 static int hf_flags_ert_present = -1;
70 static int hf_flags_close_session = -1;
71 static int hf_flags_close_object = -1;
72 static int hf_hlen = -1;
73 static int hf_codepoint = -1;
74 static int hf_cci = -1;
75 static int hf_tsi = -1;
76 static int hf_tsi16 = -1;
77 static int hf_tsi32 = -1;
78 static int hf_tsi48 = -1;
79 static int hf_toi = -1;
80 static int hf_toi16 = -1;
81 static int hf_toi32 = -1;
82 static int hf_toi48 = -1;
83 static int hf_toi64 = -1;
84 static int hf_toi_extended = -1;
85 static int hf_sct = -1;
86 static int hf_ert = -1;
87 static int hf_ext = -1;
88 static int hf_hec_type = -1;
89 static int hf_hec_len = -1;
90 static int hf_hec_data = -1;
91 static int hf_send_rate = -1;
92 static int hf_cenc = -1;
93 static int hf_flute_version = -1;
94 static int hf_fdt_instance_id = -1;
96 static int ett_main = -1;
97 static int ett_fsize = -1;
98 static int ett_flags = -1;
99 static int ett_ext = -1;
100 static int ett_ext_ext = -1;
102 /* Enumerated data types for LCT preferences */
103 const enum_val_t enum_lct_ext_192[] =
105 { "none", "Don't decode", LCT_PREFS_EXT_192_NONE },
106 { "flute", "Decode as FLUTE extension (EXT_FDT)", LCT_PREFS_EXT_192_FLUTE },
110 const enum_val_t enum_lct_ext_193[] =
112 { "none", "Don't decode", LCT_PREFS_EXT_193_NONE },
113 { "flute", "Decode as FLUTE extension (EXT_CENC)", LCT_PREFS_EXT_193_FLUTE },
117 static const value_string hec_type_vals[] = {
118 { 0, "EXT_NOP, No-Operation" },
119 { 1, "EXT_AUTH, Packet authentication" },
120 { 2, "EXT_CC, Congestion Control Feedback" },
121 { 64, "EXT_FTI, FEC Object Transmission Information" },
122 { 128, "EXT_RATE, Send Rate" },
123 { 192, "EXT_FDT, FDT Instance Header" },
124 { 193, "EXT_CENC, FDT Instance Content Encoding" },
129 /* LCT helper functions */
130 /* ==================== */
132 static void lct_timestamp_parse(guint32 t, nstime_t* s)
135 s->nsecs = (t % 1000) * 1000000;
138 double rmt_decode_send_rate(guint16 send_rate )
142 value = (send_rate >> 4) * 10.0 / 4096.0 * pow(10.0, (send_rate & 0xf));
147 int lct_ext_decode(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, guint offset, guint offset_max, lct_data_exchange_t *data_exchange,
148 int hfext, int ettext)
154 start_offset = offset;
156 proto_tree *hec_tree, *ext_tree;
158 /* Figure out the extention count */
159 while (tmp_offset < offset_max)
161 het = tvb_get_guint8(tvb, tmp_offset);
164 length = tvb_get_guint8(tvb, tmp_offset+1)*4;
171 /* Prevents infinite loops */
175 tmp_offset += length;
182 ti = proto_tree_add_uint(tree, hfext, tvb, offset, tmp_offset - offset, count);
183 hec_tree = proto_item_add_subtree(ti, ettext);
185 for (i = 0; i < count; i++)
187 het = tvb_get_guint8(tvb, offset);
190 length = tvb_get_guint8(tvb, offset+1)*4;
197 ti = proto_tree_add_item(hec_tree, hf_hec_type, tvb, offset, 1, ENC_BIG_ENDIAN);
198 ext_tree = proto_item_add_subtree(ti, ett_ext_ext);
199 proto_item_set_len(ti, length);
203 proto_tree_add_item(ext_tree, hf_hec_len, tvb, offset+1, 1, ENC_BIG_ENDIAN);
208 case 0: /* EXT_NOP */
209 case 1: /* EXT_AUTH */
211 proto_tree_add_item(ext_tree, hf_hec_data, tvb, offset+2, length-2, ENC_NA);
214 case 3: /* EXT_CC RATE */
215 proto_tree_add_text(ext_tree, tvb, offset+2, 2,
216 "CC Sequence: %u", tvb_get_ntohs(tvb, offset+2));
217 proto_tree_add_text(ext_tree, tvb, offset+4, 1,
218 "CC Flags: 0x%x", tvb_get_guint8(tvb, offset+4));
219 proto_tree_add_text(ext_tree, tvb, offset+5, 1,
220 "CC RTT: %u", tvb_get_guint8(tvb, offset+5));
221 proto_tree_add_text(ext_tree, tvb, offset+6, 2,
222 "CC Loss: %g", tvb_get_ntohs(tvb, offset+6)/65535.0);
223 proto_tree_add_text(ext_tree, tvb, offset+8, 2,
224 "CC Rate: %u", tvb_get_ntohs(tvb, offset+8));
227 case 64: /* EXT_FTI */
228 fec_decode_ext_fti(tvb, pinfo, ext_tree, offset,
229 (data_exchange == NULL) ? 0 : data_exchange->codepoint);
232 case 128: /* EXT_RATE */
233 proto_tree_add_double(ext_tree, hf_send_rate, tvb, offset+2, 2,
234 rmt_decode_send_rate(tvb_get_ntohs(tvb, offset+2)));
237 case 192: /* EXT_FDT */
238 if ((data_exchange != NULL) && (data_exchange->ext_192 == LCT_PREFS_EXT_192_FLUTE))
240 proto_tree_add_item(ext_tree, hf_flute_version, tvb, offset, 4, ENC_BIG_ENDIAN);
241 proto_tree_add_item(ext_tree, hf_fdt_instance_id, tvb, offset, 4, ENC_BIG_ENDIAN);
242 data_exchange->is_flute = TRUE;
246 case 193: /* EXT_CENC */
247 if ((data_exchange != NULL) && (data_exchange->ext_193 == LCT_PREFS_EXT_193_FLUTE))
249 proto_tree_add_item(ext_tree, hf_cenc, tvb, offset+3, 1, ENC_BIG_ENDIAN);
257 return offset-start_offset;
260 /* LCT exported functions */
261 /* ====================== */
266 /* Dissect an LCT header:
267 * l - ptr to the logical LCT packet representation to fill, and related wireshark stuffs
268 * f - ptr to the FEC infos to fill (EXT_FTI), and related wireshark stuffs
270 * pinfo - packet info
271 * tree - tree where to add LCT header subtree
272 * offset - ptr to offset to use and update
277 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
278 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279 | V | C | r |S| O |H|T|R|A|B| HDR_LEN | Codepoint (CP)|
280 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
281 | Congestion Control Information (CCI, length = 32*(C+1) bits) |
283 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
284 | Transport Session Identifier (TSI, length = 32*S+16*H bits) |
286 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
287 | Transport Object Identifier (TOI, length = 32*O+16*H bits) |
289 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290 | Sender Current Time (SCT, if T = 1) |
291 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
292 | Expected Residual Time (ERT, if R = 1) |
293 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
294 | Header Extensions (if applicable) |
296 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298 Figure 1 - Default LCT header format
302 dissect_lct(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
315 /* Set up structures needed to add the protocol subtree and manage it */
317 proto_tree *lct_tree = tree, *lct_fsize_tree, *lct_flags_tree;
319 lct_data_exchange_t *data_exchange = (lct_data_exchange_t *)data;
321 /* LCT fixed-size fields dissection */
322 /* -------------------------------- */
323 buffer16 = tvb_get_ntohs(tvb, offset);
325 cci_size = ((buffer16 & 0x0C00) >> 10) * 4 + 4;
326 tsi_size = ((buffer16 & 0x0080) >> 7) * 4 + ((buffer16 & 0x0010) >> 4) * 2;
327 toi_size = ((buffer16 & 0x0060) >> 5) * 4 + ((buffer16 & 0x0010) >> 4) * 2;
329 hlen = tvb_get_guint8(tvb, offset+2) * 4;
331 if (data_exchange != NULL)
333 data_exchange->codepoint = tvb_get_guint8(tvb, offset+3);
334 data_exchange->is_flute = FALSE;
339 /* Create the LCT subtree */
340 ti = proto_tree_add_item(tree, proto_rmt_lct, tvb, offset, hlen, ENC_NA);
341 lct_tree = proto_item_add_subtree(ti, ett_main);
343 /* Fill the LCT subtree */
344 proto_tree_add_item(lct_tree, hf_version, tvb, offset, 2, ENC_BIG_ENDIAN);
346 ti = proto_tree_add_item(lct_tree, hf_fsize_header, tvb, offset, 2, ENC_BIG_ENDIAN);
347 lct_fsize_tree = proto_item_add_subtree(ti, ett_fsize);
349 /* Fill the LCT fsize subtree */
350 proto_tree_add_uint(lct_fsize_tree, hf_fsize_cci, tvb, offset, 2, cci_size);
351 proto_tree_add_uint(lct_fsize_tree, hf_fsize_tsi, tvb, offset, 2, tsi_size);
352 proto_tree_add_uint(lct_fsize_tree, hf_fsize_toi, tvb, offset, 2, toi_size);
354 ti = proto_tree_add_item(lct_tree, hf_flags_header, tvb, offset, 2, ENC_BIG_ENDIAN);
355 lct_flags_tree = proto_item_add_subtree(ti, ett_flags);
357 /* Fill the LCT flags subtree */
358 proto_tree_add_item(lct_flags_tree, hf_flags_sct_present, tvb, offset, 2, ENC_BIG_ENDIAN);
359 proto_tree_add_item(lct_flags_tree, hf_flags_ert_present, tvb, offset, 2, ENC_BIG_ENDIAN);
360 proto_tree_add_item(lct_flags_tree, hf_flags_close_session, tvb, offset, 2, ENC_BIG_ENDIAN);
361 proto_tree_add_item(lct_flags_tree, hf_flags_close_object, tvb, offset, 2, ENC_BIG_ENDIAN);
363 proto_tree_add_uint(lct_tree, hf_hlen, tvb, offset+2, 1, hlen);
364 proto_tree_add_item(lct_tree, hf_codepoint, tvb, offset+3, 1, ENC_BIG_ENDIAN);
370 /* LCT variable-size and optional fields dissection */
371 /* ------------------------------------------------ */
373 /* Congestion Control Information (CCI) */
375 proto_tree_add_item(lct_tree, hf_cci, tvb, offset, cci_size, ENC_NA);
379 /* Transmission Session Identifier (TSI) */
385 proto_tree_add_uint(lct_tree, hf_tsi, tvb, offset, tsi_size, 0);
390 proto_tree_add_item(lct_tree, hf_tsi16, tvb, offset, tsi_size, ENC_BIG_ENDIAN);
391 tsi = tvb_get_ntohs(tvb, offset);
395 proto_tree_add_item(lct_tree, hf_tsi32, tvb, offset, tsi_size, ENC_BIG_ENDIAN);
396 tsi = tvb_get_ntohl(tvb, offset);
400 proto_tree_add_item(lct_tree, hf_tsi48, tvb, offset, tsi_size, ENC_BIG_ENDIAN);
401 tsi = tvb_get_ntoh48(tvb, offset);
408 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TSI: %" G_GINT64_MODIFIER "u", tsi);
412 /* Transmission Object Identifier (TOI) */
418 proto_tree_add_uint(lct_tree, hf_toi, tvb, offset, toi_size, 0);
423 proto_tree_add_item(lct_tree, hf_toi16, tvb, offset, toi_size, ENC_BIG_ENDIAN);
424 toi = tvb_get_ntohs(tvb, offset);
428 proto_tree_add_item(lct_tree, hf_toi32, tvb, offset, toi_size, ENC_BIG_ENDIAN);
429 toi = tvb_get_ntohl(tvb, offset);
433 proto_tree_add_item(lct_tree, hf_toi48, tvb, offset, toi_size, ENC_BIG_ENDIAN);
434 toi = tvb_get_ntoh48(tvb, offset);
438 proto_tree_add_item(lct_tree, hf_toi64, tvb, offset, toi_size, ENC_BIG_ENDIAN);
439 toi = tvb_get_ntoh64(tvb, offset);
443 proto_tree_add_item(lct_tree, hf_toi64, tvb, offset+2, 8, ENC_BIG_ENDIAN);
444 proto_tree_add_item(lct_tree, hf_toi_extended, tvb, offset, 2, ENC_BIG_ENDIAN);
448 proto_tree_add_item(lct_tree, hf_toi64, tvb, offset+4, 8, ENC_BIG_ENDIAN);
449 proto_tree_add_item(lct_tree, hf_toi_extended, tvb, offset, 4, ENC_BIG_ENDIAN);
453 proto_tree_add_item(lct_tree, hf_toi64, tvb, offset+6, 8, ENC_BIG_ENDIAN);
454 proto_tree_add_item(lct_tree, hf_toi_extended, tvb, offset, 6, ENC_BIG_ENDIAN);
461 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TOI: %" G_GINT64_MODIFIER "u", toi);
463 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TOI: 0x%s", tvb_bytes_to_ep_str(tvb, offset, toi_size));
467 if (buffer16 & LCT_CLOSE_SESSION_FLAG)
468 col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "Close session");
470 if (buffer16 & LCT_CLOSE_OBJECT_FLAG)
471 col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "Close object");
473 /* Sender Current Time (SCT) */
474 if (buffer16 & LCT_SCT_FLAG) {
475 lct_timestamp_parse(tvb_get_ntohl(tvb, offset), &tmp_time);
476 proto_tree_add_time(lct_tree, hf_sct, tvb, offset, 4, &tmp_time);
480 /* Expected Residual Time (ERT) */
481 if (buffer16 & LCT_ERT_FLAG) {
482 lct_timestamp_parse(tvb_get_ntohl(tvb, offset), &tmp_time);
483 proto_tree_add_time(lct_tree, hf_ert, tvb, offset, 4, &tmp_time);
487 /* LCT header extensions, if applicable */
488 /* ------------------------------------ */
489 lct_ext_decode(lct_tree, tvb, pinfo, offset, hlen, data_exchange, hf_ext, ett_ext);
495 proto_register_rmt_lct(void)
497 static hf_register_info hf[] = {
499 { "Version", "rmt-lct.version",
500 FT_UINT16, BASE_DEC, NULL, 0xF000,
504 { "Field size flags", "rmt-lct.fsize",
505 FT_UINT16, BASE_HEX, NULL, 0x0FD0,
509 { "Congestion Control Information field size", "rmt-lct.fsize.cci",
510 FT_UINT16, BASE_DEC, NULL, 0x0,
514 { "Transport Session Identifier field size", "rmt-lct.fsize.tsi",
515 FT_UINT16, BASE_DEC, NULL, 0x0,
519 { "Transport Object Identifier field size", "rmt-lct.fsize.toi",
520 FT_UINT16, BASE_DEC, NULL, 0x0,
524 { "Flags", "rmt-lct.flags",
525 FT_UINT16, BASE_HEX, NULL, 0x001F,
528 { &hf_flags_sct_present,
529 { "Sender Current Time present flag", "rmt-lct.flags.sct_present",
530 FT_BOOLEAN, 16, TFS(&tfs_set_notset), LCT_SCT_FLAG,
533 { &hf_flags_ert_present,
534 { "Expected Residual Time present flag", "rmt-lct.flags.ert_present",
535 FT_BOOLEAN, 16, TFS(&tfs_set_notset), LCT_ERT_FLAG,
538 { &hf_flags_close_session,
539 { "Close Session flag", "rmt-lct.flags.close_session",
540 FT_BOOLEAN, 16, TFS(&tfs_set_notset), LCT_CLOSE_SESSION_FLAG,
543 { &hf_flags_close_object,
544 { "Close Object flag", "rmt-lct.flags.close_object",
545 FT_BOOLEAN, 16, TFS(&tfs_set_notset), LCT_CLOSE_OBJECT_FLAG,
549 { "Header length", "rmt-lct.hlen",
550 FT_UINT16, BASE_DEC, NULL, 0x0,
554 { "Codepoint", "rmt-lct.codepoint",
555 FT_UINT8, BASE_DEC, NULL, 0x0,
559 { "Congestion Control Information", "rmt-lct.cci",
560 FT_BYTES, BASE_NONE, NULL, 0x0,
564 { "Transport Session Identifier", "rmt-lct.tsi",
565 FT_UINT8, BASE_DEC, NULL, 0x0,
569 { "Transport Session Identifier", "rmt-lct.tsi",
570 FT_UINT16, BASE_DEC, NULL, 0x0,
574 { "Transport Session Identifier", "rmt-lct.tsi",
575 FT_UINT32, BASE_DEC, NULL, 0x0,
579 { "Transport Session Identifier", "rmt-lct.tsi",
580 FT_UINT64, BASE_DEC, NULL, 0x0,
584 { "Transport Object Identifier", "rmt-lct.toi",
585 FT_UINT8, BASE_DEC, NULL, 0x0,
589 { "Transport Object Identifier", "rmt-lct.toi",
590 FT_UINT16, BASE_DEC, NULL, 0x0,
594 { "Transport Object Identifier", "rmt-lct.toi",
595 FT_UINT32, BASE_DEC, NULL, 0x0,
599 { "Transport Object Identifier", "rmt-lct.toi",
600 FT_UINT64, BASE_DEC, NULL, 0x0,
604 { "Transport Object Identifier (up to 64 bits)", "rmt-lct.toi",
605 FT_UINT64, BASE_DEC, NULL, 0x0,
609 { "Transport Object Identifier (bits 64-112)", "rmt-lct.toi_extended",
610 FT_UINT64, BASE_DEC, NULL, 0x0,
614 { "Sender Current Time", "rmt-lct.sct",
615 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
619 { "Expected Residual Time", "rmt-lct.ert",
620 FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
624 { "Extension count", "rmt-lct.ext",
625 FT_UINT8, BASE_DEC, NULL, 0x0,
629 { "Header Extension Type (HET)", "rmt-lct.hec.type",
630 FT_UINT8, BASE_DEC, VALS(hec_type_vals), 0x0,
634 { "Header Extension Length (HEL)", "rmt-lct.hec.len",
635 FT_UINT8, BASE_DEC, NULL, 0x0,
639 { "Header Extension Data", "rmt-lct.hec.data",
640 FT_BYTES, BASE_NONE, NULL, 0x0,
644 { "Send Rate", "rmt-lct.send_rate",
645 FT_DOUBLE, BASE_NONE, NULL, 0x0,
649 { "Content Encoding Algorithm (CENC)", "rmt-lct.cenc",
650 FT_UINT8, BASE_DEC, NULL, 0x0,
654 { "FLUTE version (V)", "rmt-lct.flute_version",
655 FT_UINT32, BASE_DEC, NULL, 0x00F00000,
658 { &hf_fdt_instance_id,
659 { "FDT Instance ID", "rmt-lct.fdt_instance_id",
660 FT_UINT32, BASE_DEC, NULL, 0x000FFFFF,
665 /* Setup protocol subtree array */
666 static gint *ett[] = {
674 /* Register the protocol name and description */
675 proto_rmt_lct = proto_register_protocol("Layered Coding Transport", "RMT-LCT", "rmt-lct");
676 new_register_dissector("rmt-lct", dissect_lct, proto_rmt_lct);
678 /* Required function calls to register the header fields and subtrees used */
679 proto_register_field_array(proto_rmt_lct, hf, array_length(hf));
680 proto_register_subtree_array(ett, array_length(ett));
684 * Editor modelines - http://www.wireshark.org/tools/modelines.html
689 * indent-tabs-mode: nil
692 * ex: set shiftwidth=4 tabstop=8 expandtab:
693 * :indentSize=4:tabSize=8:noTabs=true: