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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
51 #include <epan/packet.h>
52 #include <epan/prefs.h>
53 #include <epan/strutil.h>
54 #include <epan/garrayfix.h>
58 #include "packet-rmt-lct.h"
60 /* Enumerated data types for LCT preferences */
61 static const enum_val_t enum_lct_ext_192[] =
63 { "none", "Don't decode", LCT_PREFS_EXT_192_NONE },
64 { "flute", "Decode as FLUTE extension (EXT_FDT)", LCT_PREFS_EXT_192_FLUTE },
68 static const enum_val_t enum_lct_ext_193[] =
70 { "none", "Don't decode", LCT_PREFS_EXT_193_NONE },
71 { "flute", "Decode as FLUTE extension (EXT_CENC)", LCT_PREFS_EXT_193_FLUTE },
75 /* LCT helper functions */
76 /* ==================== */
78 static void lct_timestamp_parse(guint32 t, nstime_t* s)
81 s->nsecs = (t % 1000) * 1000000;
84 gboolean lct_ext_decode(struct _ext *e, struct _lct_prefs *prefs, tvbuff_t *tvb, proto_tree *tree, gint ett, struct _fec_ptr f)
89 gboolean is_flute = FALSE;
98 ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
99 "EXT_NOP, No-Operation (0)");
101 rmt_ext_decode_default_subtree(e, tvb, ti, ett);
109 ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
110 "EXT_AUTH, Packet authentication (1)");
112 rmt_ext_decode_default_subtree(e, tvb, ti, ett);
119 ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
120 "EXT_CC, Congestion Control Feedback (%u)", e->het);
122 ext_tree = proto_item_add_subtree(ti, ett);
123 rmt_ext_decode_default_header(e, tvb, ext_tree);
124 proto_tree_add_text(ext_tree, tvb, e->offset+2, 2,
125 "CC Sequence: %u", tvb_get_ntohs(tvb, e->offset+2));
126 proto_tree_add_text(ext_tree, tvb, e->offset+4, 1,
127 "CC Flags: 0x%x", tvb_get_guint8(tvb, e->offset+4));
128 proto_tree_add_text(ext_tree, tvb, e->offset+5, 1,
129 "CC RTT: %u", tvb_get_guint8(tvb, e->offset+5));
130 proto_tree_add_text(ext_tree, tvb, e->offset+6, 2,
131 "CC Loss: %g", tvb_get_ntohs(tvb, e->offset+6)/65535.0);
132 proto_tree_add_text(ext_tree, tvb, e->offset+8, 2,
133 "CC Rate: %u", tvb_get_ntohs(tvb, e->offset+8));
139 fec_decode_ext_fti(e, tvb, tree, ett, f);
147 ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
148 "EXT_RATE, Send Rate (%u)", e->het);
150 ext_tree = proto_item_add_subtree(ti, ett);
151 rmt_ext_decode_default_header(e, tvb, ext_tree);
152 send_rate = tvb_get_ntohs(tvb, e->offset+2);
153 value = (send_rate >> 4) * 10.0 / 4096.0 * pow(10.0, (send_rate & 0xf));
154 proto_tree_add_text(ext_tree, tvb, e->offset+2, 2,
155 "Send Rate: %g", value);
161 switch (prefs->ext_192)
163 case LCT_PREFS_EXT_192_NONE:
164 rmt_ext_decode_default(e, tvb, tree, ett);
167 case LCT_PREFS_EXT_192_FLUTE:
170 ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
171 "EXT_FDT, FDT Instance Header (192)");
173 ext_tree = proto_item_add_subtree(ti, ett);
174 buffer32 = tvb_get_ntohl(tvb, e->offset);
176 rmt_ext_decode_default_header(e, tvb, ext_tree);
178 proto_tree_add_text(ext_tree, tvb, e->offset+1, 1,
179 "FLUTE version (V): %u", (buffer32 & 0x00F00000) >> 20);
181 proto_tree_add_text(ext_tree, tvb, e->offset+1, 3,
182 "FDT Instance ID: %u", buffer32 & 0x000FFFFF);
191 switch (prefs->ext_193)
193 case LCT_PREFS_EXT_193_NONE:
194 rmt_ext_decode_default(e, tvb, tree, ett);
197 case LCT_PREFS_EXT_193_FLUTE:
200 ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
201 "EXT_CENC, FDT Instance Content Encoding (193)");
203 ext_tree = proto_item_add_subtree(ti, ett);
204 buffer32 = tvb_get_ntohl(tvb, e->offset);
206 rmt_ext_decode_default_header(e, tvb, ext_tree);
208 proto_tree_add_text(ext_tree, tvb, e->offset+1, 1,
209 "Content Encoding Algorithm (CENC): %u", (buffer32 & 0x00FF0000) >> 16);
216 rmt_ext_decode_default(e, tvb, tree, ett);
221 /* LCT exported functions */
222 /* ====================== */
227 void lct_info_column(struct _lct *lct, packet_info *pinfo)
229 if (lct->tsi_present)
230 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TSI: %" G_GINT64_MODIFIER "u", lct->tsi);
232 if (lct->toi_present)
234 if (lct->toi_size <= 8)
235 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TOI: %" G_GINT64_MODIFIER "u", lct->toi);
237 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TOI: 0x%s", bytes_to_str(lct->toi_extended, lct->toi_size));
240 if (lct->close_session)
241 col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "Close session");
243 if (lct->close_object)
244 col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "Close object");
250 /* Dissect an LCT header:
251 * l - ptr to the logical LCT packet representation to fill, and related wireshark stuffs
252 * f - ptr to the FEC infos to fill (EXT_FTI), and related wireshark stuffs
254 * pinfo - packet info
255 * tree - tree where to add LCT header subtree
256 * offset - ptr to offset to use and update
258 gboolean lct_dissector(struct _lct_ptr l, struct _fec_ptr f, tvbuff_t *tvb, proto_tree *tree, guint *offset)
264 gboolean is_flute_tmp =FALSE;
265 gboolean is_flute =FALSE;
267 /* Set up structures needed to add the protocol subtree and manage it */
269 proto_tree *lct_tree;
270 proto_tree *lct_fsize_tree;
271 proto_tree *lct_flags_tree;
272 proto_tree *lct_ext_tree;
274 /* LCT fixed-size fields dissection */
275 /* -------------------------------- */
277 offset_start = *offset;
279 buffer16 = tvb_get_ntohs(tvb, *offset);
281 l.lct->version = ((buffer16 & 0xF000) >> 12);
283 l.lct->cci_size = ((buffer16 & 0x0C00) >> 10) * 4 + 4;
284 l.lct->tsi_size = ((buffer16 & 0x0080) >> 7) * 4 + ((buffer16 & 0x0010) >> 4) * 2;
285 l.lct->toi_size = ((buffer16 & 0x0060) >> 5) * 4 + ((buffer16 & 0x0010) >> 4) * 2;
287 l.lct->tsi_present = (l.lct->tsi_size > 0);
288 l.lct->toi_present = (l.lct->toi_size > 0);
289 l.lct->sct_present = (buffer16 & 0x0008) != 0;
290 l.lct->ert_present = (buffer16 & 0x0004) != 0;
291 l.lct->close_session = (buffer16 & 0x0002) != 0;
292 l.lct->close_object = (buffer16 & 0x0001) != 0;
294 l.lct->hlen = tvb_get_guint8(tvb, *offset+2) * 4;
295 l.lct->codepoint = tvb_get_guint8(tvb, *offset+3);
297 if (l.prefs->codepoint_as_fec_encoding)
299 f.fec->encoding_id_present = TRUE;
300 f.fec->encoding_id = l.lct->codepoint;
305 /* Create the LCT subtree */
306 ti = proto_tree_add_item(tree, l.hf->header, tvb, *offset, l.lct->hlen, FALSE);
307 lct_tree = proto_item_add_subtree(ti, l.ett->main);
309 /* Fill the LCT subtree */
310 proto_tree_add_uint(lct_tree, l.hf->version, tvb, *offset, 1, l.lct->version);
312 ti = proto_tree_add_item(lct_tree, l.hf->fsize_header, tvb, *offset, 2, FALSE);
313 lct_fsize_tree = proto_item_add_subtree(ti, l.ett->fsize);
315 ti = proto_tree_add_item(lct_tree, l.hf->flags_header, tvb, *offset, 2, FALSE);
316 lct_flags_tree = proto_item_add_subtree(ti, l.ett->flags);
318 proto_tree_add_uint(lct_tree, l.hf->hlen, tvb, *offset+2, 1, l.lct->hlen);
319 proto_tree_add_uint(lct_tree, l.hf->codepoint, tvb, *offset+3, 1, l.lct->codepoint);
321 /* Fill the LCT fsize subtree */
322 proto_tree_add_uint(lct_fsize_tree, l.hf->fsize_cci, tvb, *offset, 1, l.lct->cci_size);
323 proto_tree_add_uint(lct_fsize_tree, l.hf->fsize_tsi, tvb, *offset+1, 1, l.lct->tsi_size);
324 proto_tree_add_uint(lct_fsize_tree, l.hf->fsize_toi, tvb, *offset+1, 1, l.lct->toi_size);
326 /* Fill the LCT flags subtree */
327 proto_tree_add_boolean(lct_flags_tree, l.hf->flags_sct_present, tvb, *offset+1, 1, l.lct->sct_present);
328 proto_tree_add_boolean(lct_flags_tree, l.hf->flags_ert_present, tvb, *offset+1, 1, l.lct->ert_present);
329 proto_tree_add_boolean(lct_flags_tree, l.hf->flags_close_session, tvb, *offset+1, 1, l.lct->close_session);
330 proto_tree_add_boolean(lct_flags_tree, l.hf->flags_close_object, tvb, *offset+1, 1, l.lct->close_object);
334 lct_fsize_tree = NULL;
335 lct_flags_tree = NULL;
340 /* LCT variable-size and optional fields dissection */
341 /* ------------------------------------------------ */
343 /* Congestion Control Information (CCI) */
344 if (l.lct->cci_size > 0) {
345 l.lct->cci = (guint8*) tvb_get_ptr(tvb, *offset, l.lct->cci_size);
347 proto_tree_add_bytes(lct_tree, l.hf->cci, tvb, *offset, l.lct->cci_size, l.lct->cci);
348 *offset += l.lct->cci_size;
351 /* Transmission Session Identifier (TSI) */
352 if (l.lct->tsi_present) {
354 switch (l.lct->tsi_size)
361 l.lct->tsi = tvb_get_ntohs(tvb, *offset);
365 l.lct->tsi = tvb_get_ntohl(tvb, *offset);
369 l.lct->tsi = tvb_get_ntoh64(tvb, *offset-2) & G_GINT64_CONSTANT(0x0000FFFFFFFFFFFFU);
374 proto_tree_add_uint64(lct_tree, l.hf->tsi, tvb, *offset, l.lct->tsi_size, l.lct->tsi);
375 *offset += l.lct->tsi_size;
378 /* Transmission Object Identifier (TOI) */
379 if (l.lct->toi_present) {
381 switch (l.lct->toi_size)
388 l.lct->toi = tvb_get_ntohs(tvb, *offset);
392 l.lct->toi = tvb_get_ntohl(tvb, *offset);
396 l.lct->toi = tvb_get_ntoh64(tvb, *offset-2) & G_GINT64_CONSTANT(0x0000FFFFFFFFFFFFU);
400 l.lct->toi = tvb_get_ntoh64(tvb, *offset);
404 l.lct->toi = tvb_get_ntoh64(tvb, *offset+2);
408 l.lct->toi = tvb_get_ntoh64(tvb, *offset+4);
412 l.lct->toi = tvb_get_ntoh64(tvb, *offset)+6;
416 l.lct->toi_extended = tvb_get_ptr(tvb, *offset, l.lct->toi_size);
420 if (l.lct->toi_size > 8)
421 proto_tree_add_uint64(lct_tree, l.hf->toi, tvb, *offset+(l.lct->toi_size-8), 8, l.lct->toi);
423 proto_tree_add_uint64(lct_tree, l.hf->toi, tvb, *offset, l.lct->toi_size, l.lct->toi);
425 proto_tree_add_bytes(lct_tree, l.hf->toi_extended, tvb, *offset, l.lct->toi_size, l.lct->toi_extended);
428 *offset += l.lct->toi_size;
431 /* Sender Current Time (SCT) */
432 if (l.lct->sct_present) {
433 lct_timestamp_parse(tvb_get_ntohl(tvb, *offset), &l.lct->sct);
435 proto_tree_add_time(lct_tree, l.hf->sct, tvb, *offset, 4, &l.lct->sct);
439 /* Expected Residual Time (ERT) */
440 if (l.lct->ert_present) {
441 lct_timestamp_parse(tvb_get_ntohl(tvb, *offset), &l.lct->ert);
443 proto_tree_add_time(lct_tree, l.hf->ert, tvb, *offset, 4, &l.lct->ert);
447 /* LCT header extensions, if applicable */
448 /* ------------------------------------ */
450 /* Allocate an array of _ext elements */
451 l.lct->ext = g_array_new(FALSE, TRUE, sizeof(struct _ext));
453 offset_old = *offset;
454 rmt_ext_parse(l.lct->ext, tvb, offset, offset_start + l.lct->hlen);
456 /* Resync the offset with the end of LCT header */
457 *offset = offset_start + l.lct->hlen;
459 if (l.lct->ext->len > 0)
463 /* Add the extensions subtree */
464 ti = proto_tree_add_uint(lct_tree, l.hf->ext, tvb, offset_old, *offset - offset_old, l.lct->ext->len);
465 lct_ext_tree = proto_item_add_subtree(ti, l.ett->ext);
469 /* Add the extensions to the subtree */
470 for (i = 0; i < l.lct->ext->len; i++){
471 is_flute_tmp = lct_ext_decode(&g_array_index(l.lct->ext, struct _ext, i), l.prefs, tvb, lct_ext_tree, l.ett->ext_ext, f);
472 if (is_flute_tmp == TRUE )
480 void lct_dissector_free(struct _lct *lct)
482 g_array_free(lct->ext, TRUE);
488 /* Set/Reset preferences to default values */
489 void lct_prefs_set_default(struct _lct_prefs *prefs)
491 prefs->codepoint_as_fec_encoding = TRUE;
492 prefs->ext_192 = LCT_PREFS_EXT_192_FLUTE;
493 prefs->ext_193 = LCT_PREFS_EXT_193_FLUTE;
496 /* Register preferences */
497 void lct_prefs_register(struct _lct_prefs *prefs, module_t *module)
499 prefs_register_bool_preference(module,
500 "lct.codepoint_as_fec_id",
501 "LCT Codepoint as FEC Encoding ID",
502 "Whether the LCT header Codepoint field should be considered the FEC Encoding ID of carried object",
503 &prefs->codepoint_as_fec_encoding);
505 prefs_register_enum_preference(module,
507 "LCT header extention 192",
508 "How to decode LCT header extention 192",
513 prefs_register_enum_preference(module,
515 "LCT header extention 193",
516 "How to decode LCT header extention 193",