c086bd86dbbca238342d334a6d9dc193fcc15a7f
[obnox/wireshark/wip.git] / epan / dissectors / packet-flip.c
1 /* packet-flip.c
2  * Routines for FLIP packet dissection
3  *
4  * Copyright 2009, Juha Siltanen <juha.siltanen@nsn.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 /*
28  * FLIP (Flow Layer Internal Protocol) is a proprietary protocol
29  * developed by Nokia Siemens Networks.
30  */
31
32 /*
33  * Version information
34  *
35  * Version 0.0.1, November 23rd, 2009.
36  *
37  * Support for the basic and checksum headers.
38  *
39  * Version 0.0.2, August 26th, 2010.
40  *
41  * Support for payload dissecting.
42  *
43  * Version 0.0.3, September 14th, 2010.
44  *
45  * Bugfix: sorting by protocol didn't always fill in the protocol column.
46  */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include <epan/packet.h>
53 #include <epan/etypes.h>
54 #include <epan/in_cksum.h>
55
56 #include <epan/prefs.h>
57 #include <epan/emem.h>
58 #include <epan/strutil.h>
59
60 #include "packet-rtp.h"
61 #include "packet-rtcp.h"
62 #include <epan/rtp_pt.h>
63
64 static int proto_flip = -1;
65
66 /* BASIC */
67 static int hf_flip_basic_e         = -1;
68 static int hf_flip_basic_reserved  = -1;
69 static int hf_flip_basic_flowid    = -1;
70 static int hf_flip_basic_seqnum    = -1;
71 static int hf_flip_basic_len       = -1;
72
73 /* CHECKSUM */
74 static int hf_flip_chksum_etype  = -1;
75 static int hf_flip_chksum_spare  = -1;
76 static int hf_flip_chksum_e      = -1;
77 static int hf_flip_chksum_chksum = -1;
78
79 #define FLIP_BASIC            (0)
80 #define FLIP_CHKSUM           (1)
81
82 #define FLIP_BASIC_HDR_LEN         (8)
83 #define FLIP_CHKSUM_HDR_LEN        (4)
84 #define FLIP_EXTENSION_HDR_MIN_LEN (4)
85
86 static const value_string flip_short_header_names[]={
87     { FLIP_BASIC,  "BASIC" },
88     { FLIP_CHKSUM, "CHKSUM"},
89     { 0,           NULL}
90 };
91
92 static const value_string flip_long_header_names[] = {
93     { FLIP_BASIC,  "Basic"},
94     { FLIP_CHKSUM, "Checksum"},
95     { 0,           NULL }
96 };
97
98 static const value_string flip_boolean[] = {
99     {0, "No"},
100     {1, "Yes"},
101     {0, NULL}
102 };
103
104 static const value_string flip_etype[] = {
105     { FLIP_CHKSUM, "Checksum" },
106     { 0,           NULL }
107 };
108
109 #define FLIP_PAYLOAD_DECODING_MODE_NONE      (0)
110 #define FLIP_PAYLOAD_DECODING_MODE_HEURISTIC (1)
111 #define FLIP_PAYLOAD_DECODING_MODE_FORCED    (2)
112
113 static enum_val_t flip_payload_decoding_modes[] = {
114     {"none",      "no decoding", FLIP_PAYLOAD_DECODING_MODE_NONE},
115     {"heuristic", "heuristic",   FLIP_PAYLOAD_DECODING_MODE_HEURISTIC},
116     {"forced",    "forced",      FLIP_PAYLOAD_DECODING_MODE_FORCED},
117     {NULL, NULL, 0}
118 };
119
120 static gint global_flip_payload_decoding_mode =
121     FLIP_PAYLOAD_DECODING_MODE_HEURISTIC;
122
123 static gboolean is_heur_enabled_rtp  = TRUE;
124 static gboolean is_heur_enabled_rtcp = TRUE;
125
126 static const char *global_forced_protocol = "data";
127 static gboolean is_forced_handle_ok = FALSE;
128
129 static gint ett_flip         = -1;
130 static gint ett_flip_basic   = -1;
131 static gint ett_flip_chksum  = -1;
132 static gint ett_flip_payload = -1;
133
134 static dissector_handle_t rtp_handle;
135 static dissector_handle_t rtcp_handle;
136 static dissector_handle_t data_handle;
137 static dissector_handle_t forced_handle;
138
139 /* Forward declaration. */
140 void
141 proto_reg_handoff_flip(void);
142 static gboolean
143 is_payload_rtp(tvbuff_t *tvb);
144 static gboolean
145 is_payload_rtcp(tvbuff_t *tvb);
146
147 /* Dissect the checksum extension header. */
148 static int
149 dissect_flip_chksum_hdr(tvbuff_t    *tvb,
150                         packet_info *pinfo,
151                         proto_tree  *tree,
152                         guint16     computed_chksum,
153                         gboolean    *ext_hdr_follows_ptr)
154 {
155     proto_item *item;
156     proto_tree *chksum_hdr_tree;
157     guint32  dw;
158     guint8   chksum_hdr_etype;
159     guint8   chksum_hdr_spare;
160     guint8   chksum_hdr_ext;
161     guint16  chksum_hdr_chksum;
162
163     gint bytes_dissected;
164     gint offset;
165
166     item            = NULL;
167     chksum_hdr_tree = NULL;
168
169     bytes_dissected = 0;
170     offset          = 0;
171
172     dw = tvb_get_ntohl(tvb, offset);
173     chksum_hdr_etype  = (guint8) ((dw & 0xFF000000) >> 24);
174     chksum_hdr_spare  = (guint8) ((dw & 0x00FE0000) >> 17);
175     chksum_hdr_ext    = (guint8) ((dw & 0x00010000) >> 16);
176     chksum_hdr_chksum = (guint16) (dw & 0x0000FFFF);
177
178     /* The actually shouldn't be any headers after checksum. */
179     if (chksum_hdr_ext == 1) {
180         *ext_hdr_follows_ptr = TRUE;
181     }
182     else {
183         *ext_hdr_follows_ptr = FALSE;
184     }
185
186     if (tree) {
187         item = proto_tree_add_text(tree, tvb,
188                                    offset + 0, 4, "Checksum Header");
189         chksum_hdr_tree = proto_item_add_subtree(item, ett_flip_chksum);
190
191         /* ETYPE: 8 bits */
192         proto_tree_add_uint_format_value(chksum_hdr_tree, hf_flip_chksum_etype,
193                                          tvb, offset + 0, 1, dw,
194                                          "%s", val_to_str(chksum_hdr_etype,
195                                                     flip_etype,
196                                                     "Unknown"));
197         /* SPARE: 7 bits */
198         proto_tree_add_uint_format_value(chksum_hdr_tree, hf_flip_chksum_spare,
199                                          tvb, offset + 1, 1, dw,
200                                          "%d (0x%02x)",
201                                          chksum_hdr_spare, chksum_hdr_spare);
202
203         /* EXT HDR: 1 bit */
204         proto_tree_add_uint_format_value(chksum_hdr_tree, hf_flip_chksum_e,
205                                          tvb, offset + 1, 1, dw,
206                                          "%s", val_to_str(chksum_hdr_ext,
207                                                     flip_boolean,
208                                                     "Unknown"));
209         /* CHKSUM: 16 bits. */
210         proto_tree_add_uint_format_value(
211             chksum_hdr_tree,
212             hf_flip_chksum_chksum,
213             tvb, offset + 2, 2,
214             chksum_hdr_chksum,
215             "0x%04x [%s] (computed 0x%04x)",
216             chksum_hdr_chksum,
217             ((chksum_hdr_chksum == computed_chksum) ? "Correct" : "Incorrect"),
218             computed_chksum);
219     }
220
221     /* Show faulty checksums. */
222     if (computed_chksum != chksum_hdr_chksum) {
223         col_add_fstr(pinfo->cinfo, COL_INFO,
224                      "Checksum 0x%04x [%s] (computed 0x%04x)",
225                      chksum_hdr_chksum,
226                      ((chksum_hdr_chksum == computed_chksum) ?
227                       "Correct" : "Incorrect"),
228                      computed_chksum);
229     }
230
231     bytes_dissected += FLIP_CHKSUM_HDR_LEN;
232
233     return bytes_dissected;
234
235 } /* dissect_flip_chksum_hdr() */
236
237
238 /* Detection logic grabbed from packet-rtp.c and modified. */
239
240 #define RTP_VERSION(octet)      ((octet) >> 6)
241 #define RTP_MARKER(octet)       ((octet) & 0x80)
242 #define RTP_PAYLOAD_TYPE(octet) ((octet) & 0x7F)
243
244 #define RTP_V2_HEADER_MIN_LEN 12
245
246 static gboolean
247 is_payload_rtp(tvbuff_t *tvb)
248 {
249     guint8 octet1, octet2;
250     unsigned int version;
251     unsigned int payload_type;
252     unsigned int offset;
253     gint         len_remaining;
254
255     offset = 0;
256
257     len_remaining = tvb_length_remaining(tvb, offset);
258     if (len_remaining < RTP_V2_HEADER_MIN_LEN) {
259         return FALSE;
260     }
261
262     octet1 = tvb_get_guint8(tvb, offset);
263     version = RTP_VERSION(octet1);
264
265     /* Accept only version 2. */
266     if (version != 2) {
267         return FALSE;
268     }
269
270     octet2 = tvb_get_guint8(tvb, offset + 1);
271     payload_type = RTP_PAYLOAD_TYPE(octet2);
272
273     if ((payload_type <= PT_H263)
274         ||
275         ((payload_type >= PT_UNDF_96) && (payload_type <= PT_UNDF_127))) {
276         /* OK */
277         ;
278     }
279     else {
280         return FALSE;
281     }
282
283     return TRUE;
284
285 } /* is_payload_rtp() */
286
287
288 /* Detection logic grabbed from packet-rtcp.c and modified. */
289
290 #define RTCP_SR    200
291 #define RTCP_RR    201
292 #define RTCP_BYE   203
293 #define RTCP_APP   204
294
295 #define RTCP_V2_HEADER_MIN_LEN 4
296
297 static gboolean
298 is_payload_rtcp(tvbuff_t *tvb)
299 {
300     unsigned int first_byte;
301     unsigned int packet_type;
302     unsigned int offset;
303     gint         len_remaining;
304
305     offset = 0;
306
307     len_remaining = tvb_length_remaining(tvb, offset);
308     if (len_remaining < RTCP_V2_HEADER_MIN_LEN) {
309         return FALSE;
310     }
311
312     /* Look at first byte */
313     first_byte = tvb_get_guint8(tvb, offset);
314
315     /* Are version bits set to 2? */
316     if (((first_byte & 0xC0) >> 6) != 2) {
317         return FALSE;
318     }
319
320     /* Look at packet type */
321     packet_type = tvb_get_guint8(tvb, offset + 1);
322
323     /* First packet within compound packet is supposed to be a sender
324        or receiver report.
325        - allow BYE because this happens anyway
326        - allow APP because TBCP ("PoC1") packets aren't compound... */
327     if (!((packet_type == RTCP_SR)  || (packet_type == RTCP_RR) ||
328           (packet_type == RTCP_BYE) || (packet_type == RTCP_APP))) {
329         return FALSE;
330     }
331
332     /* Overall length must be a multiple of 4 bytes */
333     if (tvb_reported_length(tvb) % 4) {
334         return FALSE;
335     }
336
337     return TRUE;
338
339 } /* is_payload_rtcp() */
340
341 /* Protocol dissection */
342 static int
343 dissect_flip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
344 {
345     proto_item *item;
346     proto_item *ti;
347     proto_tree *flip_tree;
348     proto_tree *basic_hdr_tree;
349     tvbuff_t   *flip_tvb;
350
351     guint32 dw1;
352     guint32 dw2;
353
354     /* Basic header fields. */
355     guint8   basic_hdr_ext;
356     guint8   basic_hdr_reserved;
357     guint32  basic_hdr_flow_id;
358     guint16  basic_hdr_seqnum;
359     guint16  basic_hdr_len;
360
361     gboolean ext_hdr;
362
363     gint bytes_dissected;
364     gint payload_len;
365     gint frame_len;
366     gint flip_len;
367     gint offset;
368
369     /* Error handling for basic header. */
370     gboolean is_faulty_frame;
371
372     item             = NULL;
373     ti               = NULL;
374     flip_tree        = NULL;
375     basic_hdr_tree   = NULL;
376     flip_tvb         = NULL;
377
378     ext_hdr = FALSE;
379
380     bytes_dissected = 0;
381     payload_len     = 0;
382     frame_len       = 0;
383     flip_len        = 0;
384     offset          = 0;
385
386     is_faulty_frame     = FALSE;
387
388     /* Show this protocol as FLIP. */
389     col_set_str(pinfo->cinfo, COL_PROTOCOL, "FLIP");
390
391     /*
392      * The frame can be faulty in several ways:
393      * - too short (even for the basic header)
394      * - length inconsistent (header and frame info different)
395      * - checksum doesn't check out
396      * - extension header is indicated, but the frame is too short for it
397      * - unknown extension header type
398      */
399
400     /* Check that there's enough data at least for the basic header. */
401     frame_len = tvb_length(tvb);
402     if (frame_len < FLIP_BASIC_HDR_LEN) {
403         /* Not enough. This must be a malformed packet. */
404         goto DISSECT_FLIP_EXIT;
405     }
406
407     bytes_dissected += FLIP_BASIC_HDR_LEN;
408
409     /* Process the first 32 bits of the basic header. */
410     dw1 = tvb_get_ntohl(tvb, offset + 0);
411     basic_hdr_ext      = ((dw1 & 0x80000000) >> 31);
412     basic_hdr_reserved = ((dw1 & 0x70000000) >> 24);
413     basic_hdr_flow_id  = (dw1 & 0x0FFFFFFF);
414
415     /* Process the second 32 bits of the basic header. */
416     dw2 = tvb_get_ntohl(tvb, offset + 4);
417     basic_hdr_seqnum = (guint16) ((dw2 & 0xFFFF0000) >> 16);
418     basic_hdr_len    = (guint16) (dw2 & 0x0000FFFF);
419
420     /* Does the basic header indicate that an extension is next? */
421     if (basic_hdr_ext == 1) {
422         ext_hdr = TRUE;
423     }
424
425     flip_len = basic_hdr_len;
426
427     /*
428      * Check the length value.
429      */
430     if ((flip_len < FLIP_BASIC_HDR_LEN) || (flip_len > frame_len)) {
431         /* Faulty frame. Show the basic header anyway for debugging. */
432         is_faulty_frame = TRUE;
433     }
434
435     /* Fill in the info column. */
436     col_add_fstr(pinfo->cinfo, COL_INFO,
437                  "FlowID %s", val_to_str(basic_hdr_flow_id, NULL, "0x%08x"));
438
439     flip_tvb = tvb_new_subset(tvb, 0, frame_len, frame_len);
440
441     /* We are asked for details. */
442     if (tree) {
443         if (PTREE_DATA(tree)->visible) {
444             ti = proto_tree_add_protocol_format(
445                 tree, proto_flip, flip_tvb, 0, flip_len,
446                 "NSN FLIP, FlowID %s",
447                 val_to_str(basic_hdr_flow_id, NULL, "0x%08x"));
448         }
449         else {
450             ti = proto_tree_add_item(tree, proto_flip, flip_tvb, 0,
451                                      flip_len, FALSE);
452         }
453         flip_tree = proto_item_add_subtree(ti, ett_flip);
454
455         /* basic header */
456         item = proto_tree_add_text(flip_tree, flip_tvb, 0, 8, "Basic Header");
457         basic_hdr_tree = proto_item_add_subtree(item, ett_flip_basic);
458
459         /* Extension header follows? 1 bit. */
460         proto_tree_add_uint_format_value(basic_hdr_tree,
461                                          hf_flip_basic_e,
462                                          flip_tvb, offset + 0, 1, dw1,
463                                          "%s", val_to_str(basic_hdr_ext,
464                                                     flip_boolean,
465                                                     "Unknown"));
466         /* Reserved: 3 bits. */
467         proto_tree_add_uint_format_value(basic_hdr_tree,
468                                          hf_flip_basic_reserved,
469                                          flip_tvb, offset + 0, 1, dw1,
470                                          "%d", basic_hdr_reserved);
471         /* Flow ID: 28 bits. */
472         proto_tree_add_item(basic_hdr_tree, hf_flip_basic_flowid,
473                             flip_tvb, offset + 0, 4, ENC_BIG_ENDIAN);
474
475         /* Sequence number: 16 bits. */
476         proto_tree_add_uint_format_value(basic_hdr_tree, hf_flip_basic_seqnum,
477                                          flip_tvb, offset + 4, 2, dw2,
478                                          "%d (0x%04x)",
479                                          basic_hdr_seqnum, basic_hdr_seqnum);
480         /* Packet length: 16 bits. */
481         proto_tree_add_uint_format_value(basic_hdr_tree, hf_flip_basic_len,
482                                          flip_tvb, offset + 6, 2, dw2,
483                                          "%d (0x%04x)",
484                                          basic_hdr_len, basic_hdr_len);
485     }
486
487     offset += FLIP_BASIC_HDR_LEN;
488
489     /*
490      * Process faults found when parsing the basic header.
491      */
492     if (is_faulty_frame == TRUE) {
493         if (flip_len > frame_len) {
494             col_add_fstr(pinfo->cinfo, COL_INFO,
495                          "Length mismatch: frame %d bytes, hdr %d bytes",
496                          frame_len, flip_len);
497         }
498         else if (flip_len < FLIP_BASIC_HDR_LEN) {
499             col_add_fstr(pinfo->cinfo, COL_INFO,
500                          "Invalid length in basic header: %d bytes", flip_len);
501         }
502
503         goto DISSECT_FLIP_EXIT;
504     }
505
506     /*
507      * Now we know that the basic header is sensible.
508      */
509     payload_len  = basic_hdr_len;
510     payload_len -= FLIP_BASIC_HDR_LEN;
511
512     /*
513      * Dissect extension headers (if any).
514      */
515     if ((ext_hdr == TRUE) && (payload_len < FLIP_EXTENSION_HDR_MIN_LEN)) {
516         col_add_fstr(pinfo->cinfo, COL_INFO,
517                      "Extension header indicated, but not enough data");
518         goto DISSECT_FLIP_EXIT;
519     }
520
521     while ((ext_hdr == TRUE) && (payload_len >= FLIP_EXTENSION_HDR_MIN_LEN)) {
522         /* Detect the next header type. */
523         guint8  ext_hdr_type;
524         gint    bytes_handled;
525         guint16 computed_chksum;
526
527         tvbuff_t *chksum_tvb;
528
529         ext_hdr_type = tvb_get_guint8(flip_tvb, offset);
530
531         switch (ext_hdr_type) {
532         case FLIP_CHKSUM:
533             /* Calculate checksum, let the chksum dissector verify it. */
534             {
535                 vec_t   vec[2];
536
537                 vec[0].ptr = tvb_get_ptr(flip_tvb, 0, bytes_dissected + 2);
538                 vec[0].len = bytes_dissected + 2;
539                 vec[1].ptr = tvb_get_ptr(flip_tvb, bytes_dissected + 4,
540                                          flip_len - (bytes_dissected + 4));
541                 vec[1].len = flip_len - (bytes_dissected + 4);
542                 computed_chksum = in_cksum(&vec[0], 2);
543
544                 /* Checksums handled in network order. */
545                 computed_chksum = g_htons(computed_chksum);
546             }
547
548             chksum_tvb = tvb_new_subset(flip_tvb, offset,
549                                         FLIP_CHKSUM_HDR_LEN,
550                                         FLIP_CHKSUM_HDR_LEN);
551
552             /* Note that flip_tree is NULL if no details are requested. */
553             bytes_handled = dissect_flip_chksum_hdr(chksum_tvb,
554                                                     pinfo,
555                                                     flip_tree,
556                                                     computed_chksum,
557                                                     &ext_hdr);
558             bytes_dissected += bytes_handled;
559             payload_len     -= bytes_handled;
560             offset          += bytes_handled;
561             break;
562
563         default:
564             /* Unknown header type. */
565             col_add_fstr(pinfo->cinfo, COL_INFO,
566                          "Invalid extension header type 0x%02x", ext_hdr_type);
567             goto DISSECT_FLIP_EXIT;
568             break;
569         }
570     }
571
572     /*
573      * Show payload (if any) as bytes.
574      */
575     if (payload_len > 0) {
576
577         dissector_handle_t handle;
578         tvbuff_t           *payload_tvb;
579         gint               data_len;
580         gboolean           has_user_messed_up;
581
582         data_len = 0;
583         has_user_messed_up = FALSE;
584
585         payload_tvb = tvb_new_subset(flip_tvb, offset,
586                                      payload_len, payload_len);
587
588         /*
589          * 1) no decoding -> data
590          * 2) heuristic decoding
591          * 3) forced decoding
592          */
593         switch (global_flip_payload_decoding_mode) {
594         case FLIP_PAYLOAD_DECODING_MODE_NONE:
595             /* Dissect as data. */
596             handle = data_handle;
597             break;
598
599         case FLIP_PAYLOAD_DECODING_MODE_HEURISTIC:
600             if ((is_heur_enabled_rtp == TRUE)
601                 &&
602                 (is_payload_rtp(payload_tvb) == TRUE)) {
603                 /* Dissect as RTP. */
604                 handle = rtp_handle;
605             }
606             else if ((is_heur_enabled_rtcp == TRUE)
607                      &&
608                      (is_payload_rtcp(payload_tvb))) {
609                 /* Dissect as RTCP. */
610                 handle = rtcp_handle;
611             }
612             else {
613                 /* Dissect as data. */
614                 handle = data_handle;
615             }
616             break;
617
618         case FLIP_PAYLOAD_DECODING_MODE_FORCED:
619             if (is_forced_handle_ok == TRUE) {
620                 handle = forced_handle;
621             }
622             else {
623                 /* Use data as backup. */
624                 handle = data_handle;
625
626                 /* Tell the user he messed up. */
627                 has_user_messed_up = TRUE;
628             }
629             break;
630
631         default:
632             /* Fault in dissector's internal logic. */
633             DISSECTOR_ASSERT(0);
634             break;
635         }
636
637         /*
638          * If tree is NULL, we still cannot quit, we must give
639          * the RTP/RTCP/data dissectors a chance to fill in
640          * the protocol column.
641          */
642         data_len = call_dissector(handle, payload_tvb, pinfo, tree);
643
644         if (has_user_messed_up == TRUE) {
645             col_add_fstr(pinfo->cinfo, COL_INFO,
646                          "Invalid user dissector \"%s\"",
647                          global_forced_protocol);
648         }
649
650         bytes_dissected += data_len;
651
652     } /* if (payload_len > 0) */
653
654 DISSECT_FLIP_EXIT:
655     return bytes_dissected;
656
657 } /* dissect_flip() */
658
659
660 /* Protocol initialization */
661 void
662 proto_register_flip(void)
663 {
664     static hf_register_info hf[] = {
665         /*
666          * Basic header.
667          */
668         {&hf_flip_basic_e,
669          {"Extension Header Follows", "flip.basic.e", FT_UINT32, BASE_DEC,
670           VALS(flip_boolean), 0x80000000, NULL, HFILL}
671         },
672         {&hf_flip_basic_reserved,
673          {"Reserved", "flip.basic.reserved", FT_UINT32, BASE_DEC,
674           NULL, 0x70000000, "Basic Header Reserved", HFILL}
675         },
676         {&hf_flip_basic_flowid,
677          {"FlowID", "flip.basic.flowid", FT_UINT32, BASE_HEX,
678           NULL, 0x0FFFFFFF, "Basic Header Flow ID", HFILL}
679         },
680         {&hf_flip_basic_seqnum,
681          {"Seqnum", "flip.basic.seqnum", FT_UINT32, BASE_DEC,
682           NULL, 0xFFFF0000, "Basic Header Sequence Number", HFILL}
683         },
684         {&hf_flip_basic_len,
685          {"Len", "flip.basic.len", FT_UINT32, BASE_DEC,
686           NULL, 0x0000FFFF, "Basic Header Packet Length", HFILL}
687         },
688         /*
689          * Checksum header.
690          */
691         {&hf_flip_chksum_etype,
692          {"Extension Type", "flip.chksum.etype", FT_UINT32, BASE_DEC,
693           VALS(flip_etype), 0xFF000000, "Checksum Header Extension Type", HFILL}
694         },
695         {&hf_flip_chksum_spare,
696          {"Spare", "flip.chksum.spare", FT_UINT32, BASE_DEC,
697           NULL, 0x00FE0000, "Checksum Header Spare", HFILL}
698         },
699         {&hf_flip_chksum_e,
700          {"Extension Header Follows", "flip.chksum.e", FT_UINT32, BASE_DEC,
701           VALS(flip_boolean), 0x00010000, NULL, HFILL}
702         },
703         {&hf_flip_chksum_chksum,
704          {"Checksum", "flip.chksum.chksum", FT_UINT32, BASE_HEX,
705           NULL, 0x0000FFFF, NULL, HFILL}
706         }
707     };
708
709     static gint *ett[] = {
710         &ett_flip,
711         &ett_flip_basic,
712         &ett_flip_chksum,
713         &ett_flip_payload
714     };
715
716     module_t *flip_module;
717
718     proto_flip = proto_register_protocol(
719         "NSN FLIP", /* name */
720         "FLIP",     /* short name */
721         "flip"      /* abbrev */
722         );
723
724     proto_register_field_array(proto_flip, hf, array_length(hf));
725     proto_register_subtree_array(ett, array_length(ett));
726
727
728     flip_module = prefs_register_protocol(proto_flip,
729                                           proto_reg_handoff_flip);
730
731     /* Register preferences */
732     prefs_register_enum_preference(
733         flip_module,
734         "decoding_mode",
735         "FLIP payload decoding mode",
736         "Decode FLIP payload according to mode",
737         &global_flip_payload_decoding_mode,
738         flip_payload_decoding_modes,
739         TRUE);
740
741     prefs_register_static_text_preference(
742         flip_module,
743         "heur_enabled_protocols",
744         "Heuristic mode: enabled protocols",
745         "Enabled protocols for heuristic mode");
746
747     prefs_register_bool_preference(
748         flip_module,
749         "heur_decode_rtp",
750         "RTP",
751         "Decode payload as RTP if detected",
752         &is_heur_enabled_rtp);
753
754     prefs_register_bool_preference(
755         flip_module,
756         "heur_decode_rtcp",
757         "RTCP",
758         "Decode payload as RTCP if detected",
759         &is_heur_enabled_rtcp);
760
761     prefs_register_static_text_preference(
762         flip_module,
763         "forced_protocol",
764         "Forced mode: decode to user-specified protocol",
765         "Mapping of flow IDs to their decodings");
766
767     prefs_register_string_preference(
768         flip_module,
769         "forced_decode",
770         "Protocol name",
771         "Decoding to user-defined protocol",
772         &global_forced_protocol);
773
774 } /* proto_register_flip() */
775
776 /* Protocol handoff */
777 void
778 proto_reg_handoff_flip(void)
779 {
780     dissector_handle_t flip_handle;
781
782     static gboolean flip_prefs_initialized = FALSE;
783
784     if (flip_prefs_initialized == FALSE) {
785         flip_handle = new_create_dissector_handle(dissect_flip, proto_flip);
786         dissector_add_uint("ethertype", ETHERTYPE_FLIP, flip_handle);
787
788         rtp_handle  = find_dissector("rtp");
789         rtcp_handle = find_dissector("rtcp");
790         data_handle = find_dissector("data");
791
792         flip_prefs_initialized = TRUE;
793     }
794
795     /* Preferences update: check user-specified dissector. */
796     is_forced_handle_ok = FALSE;
797     forced_handle = find_dissector(global_forced_protocol);
798     if (forced_handle != NULL) {
799         is_forced_handle_ok = TRUE;
800     }
801
802 } /* proto_reg_handoff_flip() */
803
804 /* end of file packet-flip.c */