Removed some more "statement not reached" warnings.
[obnox/wireshark/wip.git] / epan / dissectors / packet-rmt-lct.c
1 /* packet-rmt-lct.c
2  * Reliable Multicast Transport (RMT)
3  * LCT Building Block dissector
4  * Copyright 2005, Stefano Pettini <spettini@users.sourceforge.net>
5  *
6  * Layered Coding Transport (LCT):
7  * -------------------------------
8  *
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.
16  *
17  * References:
18  *     RFC 3451, Layered Coding Transport (LCT) Building Block
19  *
20  * $Id$
21  *
22  * Wireshark - Network traffic analyzer
23  * By Gerald Combs <gerald@wireshark.org>
24  * Copyright 1998 Gerald Combs
25  *
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.
30  *
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.
35  *
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.
39  */
40
41 #ifdef HAVE_CONFIG_H
42 # include "config.h"
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include <glib.h>
50
51 #include <epan/packet.h>
52 #include <epan/prefs.h>
53 #include <epan/strutil.h>
54 #include <epan/garrayfix.h>
55
56 #include <math.h>
57
58 #include "packet-rmt-lct.h"
59
60 /* Enumerated data types for LCT preferences */
61 static const enum_val_t enum_lct_ext_192[] =
62 {
63         { "none", "Don't decode", LCT_PREFS_EXT_192_NONE },
64         { "flute", "Decode as FLUTE extension (EXT_FDT)", LCT_PREFS_EXT_192_FLUTE },
65         { NULL, NULL, 0 }
66 };
67
68 static const enum_val_t enum_lct_ext_193[] =
69 {
70         { "none", "Don't decode", LCT_PREFS_EXT_193_NONE },
71         { "flute", "Decode as FLUTE extension (EXT_CENC)", LCT_PREFS_EXT_193_FLUTE },
72         { NULL, NULL, 0 }
73 };
74
75 /* LCT helper functions */
76 /* ==================== */
77
78 static void lct_timestamp_parse(guint32 t, nstime_t* s)
79 {
80         s->secs = t / 1000;
81         s->nsecs = (t % 1000) * 1000000;
82 }
83
84 gboolean lct_ext_decode(struct _ext *e, struct _lct_prefs *prefs, tvbuff_t *tvb, proto_tree *tree, gint ett, struct _fec_ptr f)
85 {
86         guint32 buffer32;
87         proto_item *ti;
88         proto_tree *ext_tree;
89         gboolean is_flute = FALSE;
90
91         switch (e->het)
92         {
93
94         /* EXT_NOP */
95         case 0:
96                 if (tree)
97                 {
98                         ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
99                                 "EXT_NOP, No-Operation (0)");
100
101                         rmt_ext_decode_default_subtree(e, tvb, ti, ett);
102                 }
103                 break;
104
105         /* EXT_AUTH */
106         case 1:
107                 if (tree)
108                 {
109                         ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
110                                 "EXT_AUTH, Packet authentication (1)");
111
112                         rmt_ext_decode_default_subtree(e, tvb, ti, ett);
113                 }
114                 break;
115
116     /* EXT_CC RATE */
117     case 3:
118         if (tree) {
119                         ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
120                                 "EXT_CC, Congestion Control Feedback (%u)", e->het);
121
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));
134
135                 }
136                 break;
137         /* EXT_FTI */
138         case 64:
139                 fec_decode_ext_fti(e, tvb, tree, ett, f);
140                 break;
141
142         /* EXT_RATE */
143     case 128:
144         if (tree) {
145                         guint16 send_rate;
146                         double value;
147                         ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
148                                 "EXT_RATE, Send Rate (%u)", e->het);
149
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);
156                 }
157                 break;
158
159         /* EXT_FDT */
160         case 192:
161                 switch (prefs->ext_192)
162                 {
163                 case LCT_PREFS_EXT_192_NONE:
164                         rmt_ext_decode_default(e, tvb, tree, ett);
165                         break;
166
167                 case LCT_PREFS_EXT_192_FLUTE:
168                         if (tree)
169                         {
170                                 ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
171                                         "EXT_FDT, FDT Instance Header (192)");
172
173                                 ext_tree = proto_item_add_subtree(ti, ett);
174                                 buffer32 = tvb_get_ntohl(tvb, e->offset);
175
176                                 rmt_ext_decode_default_header(e, tvb, ext_tree);
177
178                                 proto_tree_add_text(ext_tree, tvb, e->offset+1, 1,
179                                         "FLUTE version (V): %u", (buffer32 & 0x00F00000) >> 20);
180
181                                 proto_tree_add_text(ext_tree, tvb, e->offset+1, 3,
182                                         "FDT Instance ID: %u", buffer32 & 0x000FFFFF);
183                         }
184                         is_flute = TRUE;
185                         break;
186                 }
187                 break;
188
189         /* EXT_CENC */
190         case 193:
191                 switch (prefs->ext_193)
192                 {
193                 case LCT_PREFS_EXT_193_NONE:
194                         rmt_ext_decode_default(e, tvb, tree, ett);
195                         break;
196
197                 case LCT_PREFS_EXT_193_FLUTE:
198                         if (tree)
199                         {
200                                 ti = proto_tree_add_text(tree, tvb, e->offset, e->length,
201                                         "EXT_CENC, FDT Instance Content Encoding (193)");
202
203                                 ext_tree = proto_item_add_subtree(ti, ett);
204                                 buffer32 = tvb_get_ntohl(tvb, e->offset);
205
206                                 rmt_ext_decode_default_header(e, tvb, ext_tree);
207
208                                 proto_tree_add_text(ext_tree, tvb, e->offset+1, 1,
209                                         "Content Encoding Algorithm (CENC): %u", (buffer32 & 0x00FF0000) >> 16);
210                         }
211                         break;
212                 }
213                 break;
214
215         default:
216                 rmt_ext_decode_default(e, tvb, tree, ett);
217         }
218         return is_flute;
219 }
220
221 /* LCT exported functions */
222 /* ====================== */
223
224 /* Info */
225 /* ---- */
226
227 void lct_info_column(struct _lct *lct, packet_info *pinfo)
228 {
229         if (lct->tsi_present)
230                 col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TSI: %" G_GINT64_MODIFIER "u", lct->tsi);
231
232         if (lct->toi_present)
233         {
234                 if (lct->toi_size <= 8)
235                         col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TOI: %" G_GINT64_MODIFIER "u", lct->toi);
236                 else
237                         col_append_sep_fstr(pinfo->cinfo, COL_INFO, " ", "TOI: 0x%s", bytes_to_str(lct->toi_extended, lct->toi_size));
238         }
239
240         if (lct->close_session)
241                 col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "Close session");
242
243         if (lct->close_object)
244                 col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "Close object");
245 }
246
247 /* Dissection */
248 /* ---------- */
249
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
253  * tvb - buffer
254  * pinfo - packet info
255  * tree - tree where to add LCT header subtree
256  * offset - ptr to offset to use and update
257  */
258 gboolean lct_dissector(struct _lct_ptr l, struct _fec_ptr f, tvbuff_t *tvb, proto_tree *tree, guint *offset)
259 {
260         guint i;
261         guint offset_old;
262         guint offset_start;
263         guint16 buffer16;
264         gboolean is_flute_tmp =FALSE;
265         gboolean is_flute =FALSE;
266
267         /* Set up structures needed to add the protocol subtree and manage it */
268         proto_item *ti;
269         proto_tree *lct_tree;
270         proto_tree *lct_fsize_tree;
271         proto_tree *lct_flags_tree;
272         proto_tree *lct_ext_tree;
273
274         /* LCT fixed-size fields dissection */
275         /* -------------------------------- */
276
277         offset_start = *offset;
278
279         buffer16 = tvb_get_ntohs(tvb, *offset);
280
281         l.lct->version = ((buffer16 & 0xF000) >> 12);
282
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;
286
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;
293
294         l.lct->hlen = tvb_get_guint8(tvb, *offset+2) * 4;
295         l.lct->codepoint = tvb_get_guint8(tvb, *offset+3);
296
297         if (l.prefs->codepoint_as_fec_encoding)
298         {
299                 f.fec->encoding_id_present = TRUE;
300                 f.fec->encoding_id = l.lct->codepoint;
301         }
302
303         if (tree)
304         {
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);
308
309                 /* Fill the LCT subtree */
310                 proto_tree_add_uint(lct_tree, l.hf->version, tvb, *offset, 1, l.lct->version);
311
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);
314
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);
317
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);
320
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);
325
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);
331
332         } else {
333                 lct_tree = NULL;
334                 lct_fsize_tree = NULL;
335                 lct_flags_tree = NULL;
336         }
337
338         *offset += 4;
339
340         /* LCT variable-size and optional fields dissection */
341         /* ------------------------------------------------ */
342
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);
346                 if (tree)
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;
349         }
350
351         /* Transmission Session Identifier (TSI) */
352         if (l.lct->tsi_present) {
353
354                 switch (l.lct->tsi_size)
355                 {
356                         case 0:
357                                 l.lct->tsi = 0;
358                                 break;
359
360                         case 2:
361                                 l.lct->tsi = tvb_get_ntohs(tvb, *offset);
362                                 break;
363
364                         case 4:
365                                 l.lct->tsi = tvb_get_ntohl(tvb, *offset);
366                                 break;
367
368                         case 6:
369                                 l.lct->tsi = tvb_get_ntoh64(tvb, *offset-2) & G_GINT64_CONSTANT(0x0000FFFFFFFFFFFFU);
370                                 break;
371                 }
372
373                 if (tree)
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;
376         }
377
378         /* Transmission Object Identifier (TOI) */
379         if (l.lct->toi_present) {
380
381                 switch (l.lct->toi_size)
382                 {
383                         case 0:
384                                 l.lct->toi = 0;
385                                 break;
386
387                         case 2:
388                                 l.lct->toi = tvb_get_ntohs(tvb, *offset);
389                                 break;
390
391                         case 4:
392                                 l.lct->toi = tvb_get_ntohl(tvb, *offset);
393                                 break;
394
395                         case 6:
396                                 l.lct->toi = tvb_get_ntoh64(tvb, *offset-2) & G_GINT64_CONSTANT(0x0000FFFFFFFFFFFFU);
397                                 break;
398
399                         case 8:
400                                 l.lct->toi = tvb_get_ntoh64(tvb, *offset);
401                                 break;
402
403                         case 10:
404                                 l.lct->toi = tvb_get_ntoh64(tvb, *offset+2);
405                                 break;
406
407                         case 12:
408                                 l.lct->toi = tvb_get_ntoh64(tvb, *offset+4);
409                                 break;
410
411                         case 14:
412                                 l.lct->toi = tvb_get_ntoh64(tvb, *offset)+6;
413                                 break;
414                 }
415
416                 l.lct->toi_extended = tvb_get_ptr(tvb, *offset, l.lct->toi_size);
417
418                 if (tree)
419                 {
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);
422                         else
423                                 proto_tree_add_uint64(lct_tree, l.hf->toi, tvb, *offset, l.lct->toi_size, l.lct->toi);
424
425                         proto_tree_add_bytes(lct_tree, l.hf->toi_extended, tvb, *offset, l.lct->toi_size, l.lct->toi_extended);
426                 }
427
428                 *offset += l.lct->toi_size;
429         }
430
431         /* Sender Current Time (SCT) */
432         if (l.lct->sct_present) {
433                 lct_timestamp_parse(tvb_get_ntohl(tvb, *offset), &l.lct->sct);
434                 if (tree)
435                         proto_tree_add_time(lct_tree, l.hf->sct, tvb, *offset, 4, &l.lct->sct);
436                 *offset += 4;
437         }
438
439         /* Expected Residual Time (ERT) */
440         if (l.lct->ert_present) {
441                 lct_timestamp_parse(tvb_get_ntohl(tvb, *offset), &l.lct->ert);
442                 if (tree)
443                         proto_tree_add_time(lct_tree, l.hf->ert, tvb, *offset, 4, &l.lct->ert);
444                 *offset += 4;
445         }
446
447         /* LCT header extensions, if applicable */
448         /* ------------------------------------ */
449
450         /* Allocate an array of _ext elements */
451         l.lct->ext = g_array_new(FALSE, TRUE, sizeof(struct _ext));
452
453         offset_old = *offset;
454         rmt_ext_parse(l.lct->ext, tvb, offset, offset_start + l.lct->hlen);
455
456         /* Resync the offset with the end of LCT header */
457         *offset = offset_start + l.lct->hlen;
458
459         if (l.lct->ext->len > 0)
460         {
461                 if (tree)
462                 {
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);
466                 } else
467                         lct_ext_tree = NULL;
468
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 )
473                                 is_flute = TRUE;
474                 }
475         }
476
477         return is_flute;
478 }
479
480 void lct_dissector_free(struct _lct *lct)
481 {
482         g_array_free(lct->ext, TRUE);
483 }
484
485 /* Preferences */
486 /* ----------- */
487
488 /* Set/Reset preferences to default values */
489 void lct_prefs_set_default(struct _lct_prefs *prefs)
490 {
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;
494 }
495
496 /* Register preferences */
497 void lct_prefs_register(struct _lct_prefs *prefs, module_t *module)
498 {
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);
504
505         prefs_register_enum_preference(module,
506                 "lct.ext.192",
507                 "LCT header extention 192",
508                 "How to decode LCT header extention 192",
509                 &prefs->ext_192,
510                 enum_lct_ext_192,
511                 FALSE);
512
513         prefs_register_enum_preference(module,
514                 "lct.ext.193",
515                 "LCT header extention 193",
516                 "How to decode LCT header extention 193",
517                 &prefs->ext_193,
518                 enum_lct_ext_193,
519                 FALSE);
520 }