Replace a couple more calls to tvb_get_string() with tvb_get_ephemeral_string()....
[obnox/wireshark/wip.git] / epan / dissectors / packet-dcp-etsi.c
1 /* packet-dcp-etsi.c
2  * Routines for ETSI Distribution & Communication Protocol
3  * Copyright 2006, British Broadcasting Corporation
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  *
25  * Protocol info
26  * Ref: ETSI DCP (ETSI TS 102 821)
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <gmodule.h>
34 #include <epan/packet.h>
35 #include <epan/prefs.h>
36 #include <epan/reassemble.h>
37 #include <epan/crcdrm.h>
38 #include <epan/reedsolomon.h>
39 #include <epan/emem.h>
40 #include <string.h>
41
42 /* forward reference */
43
44 static gboolean dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
45 static void dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
46 static void dissect_pft (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
47 static void dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
48
49 static dissector_table_t dcp_dissector_table;
50 static dissector_table_t af_dissector_table;
51 static dissector_table_t tpl_dissector_table;
52
53 static int proto_dcp_etsi = -1;
54 static int proto_af = -1;
55 static int proto_pft = -1;
56 static int proto_tpl = -1;
57 static dissector_handle_t af_handle;
58 static dissector_handle_t pft_handle;
59 static dissector_handle_t tpl_handle;
60 static int hf_edcp_sync = -1;
61 static int hf_edcp_len = -1;
62 static int hf_edcp_seq = -1;
63 static int hf_edcp_crcflag = -1;
64 static int hf_edcp_maj = -1;
65 static int hf_edcp_min = -1;
66 static int hf_edcp_pt = -1;
67 static int hf_edcp_crc = -1;
68 static int hf_edcp_crc_ok = -1;
69 static int hf_edcp_pft_pt = -1;
70 static int hf_edcp_pseq = -1;
71 static int hf_edcp_findex = -1;
72 static int hf_edcp_fcount = -1;
73 static int hf_edcp_fecflag = -1;
74 static int hf_edcp_addrflag = -1;
75 static int hf_edcp_plen = -1;
76 static int hf_edcp_rsk = -1;
77 static int hf_edcp_rsz = -1;
78 static int hf_edcp_source = -1;
79 static int hf_edcp_dest = -1;
80 static int hf_edcp_hcrc = -1;
81 static int hf_edcp_hcrc_ok = -1;
82 static int hf_edcp_c_max = -1;
83 static int hf_edcp_rx_min = -1;
84 static int hf_edcp_rs_corrected = -1;
85 static int hf_edcp_rs_ok = -1;
86 static int hf_edcp_pft_payload = -1;
87
88 static int hf_tpl_tlv = -1;
89 static int hf_tpl_ptr = -1;
90
91 static int hf_edcp_fragments = -1;
92 static int hf_edcp_fragment = -1;
93 static int hf_edcp_fragment_overlap = -1;
94 static int hf_edcp_fragment_overlap_conflicts = -1;
95 static int hf_edcp_fragment_multiple_tails = -1;
96 static int hf_edcp_fragment_too_long_fragment = -1;
97 static int hf_edcp_fragment_error = -1;
98 static int hf_edcp_reassembled_in = -1;
99
100 /* Initialize the subtree pointers */
101 static gint ett_edcp = -1;
102 static gint ett_af = -1;
103 static gint ett_pft = -1;
104 static gint ett_tpl = -1;
105 static gint ett_edcp_fragment = -1;
106 static gint ett_edcp_fragments = -1;
107
108 static GHashTable *dcp_fragment_table = NULL;
109 static GHashTable *dcp_reassembled_table = NULL;
110
111 static const fragment_items dcp_frag_items = {
112 /* Fragment subtrees */
113   &ett_edcp_fragment,
114   &ett_edcp_fragments,
115 /* Fragment fields */
116   &hf_edcp_fragments,
117   &hf_edcp_fragment,
118   &hf_edcp_fragment_overlap,
119   &hf_edcp_fragment_overlap_conflicts,
120   &hf_edcp_fragment_multiple_tails,
121   &hf_edcp_fragment_too_long_fragment,
122   &hf_edcp_fragment_error,
123 /* Reassembled in field */
124   &hf_edcp_reassembled_in,
125 /* Tag */
126   "Message fragments"
127 };
128
129 /** initialise the DCP protocol. Details follow
130  *  here.
131  */
132 static void
133 dcp_init_protocol(void)
134 {
135   fragment_table_init (&dcp_fragment_table);
136   reassembled_table_init (&dcp_reassembled_table);
137 }
138
139
140 /** Dissect a DCP packet. Details follow
141  *  here.
142  *  \param[in,out] tvb The buffer containing the packet
143  *  \param[in,out] pinfo The packet info structure
144  *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
145 static void
146  */
147 static gboolean
148 dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
149 {
150   guint8 *sync;
151   proto_tree *dcp_tree = NULL;
152   sync = tvb_get_ephemeral_string (tvb, 0, 2);
153   if((sync[0]!='A' && sync[0]!='P') || sync[1]!='F')
154     return FALSE;
155
156   pinfo->current_proto = "DCP (ETSI)";
157
158   /* Clear out stuff in the info column */
159   if (check_col (pinfo->cinfo, COL_INFO)) {
160     col_clear (pinfo->cinfo, COL_INFO);
161   }
162   if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
163     col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP (ETSI)");
164     /*col_append_fstr (pinfo->cinfo, COL_INFO, " tvb %d", tvb_length(tvb));*/
165   }
166
167   if(tree) {
168     proto_item *ti = NULL;
169     ti = proto_tree_add_item (tree, proto_dcp_etsi, tvb, 0, -1, FALSE);
170     dcp_tree = proto_item_add_subtree (ti, ett_edcp);
171   }
172
173   dissector_try_string(dcp_dissector_table, (char*)sync, tvb, pinfo, dcp_tree);
174   return TRUE;
175 }
176
177 #define PFT_RS_N_MAX 207
178 #define PFT_RS_K 255
179 #define PFT_RS_P (PFT_RS_K - PFT_RS_N_MAX)
180
181
182 static
183 void rs_deinterleave(const guint8 *input, guint8 *output, guint16 plen, guint32 fcount)
184 {
185   guint fidx;
186   for(fidx=0; fidx<fcount; fidx++)
187   {
188     int r;
189     for (r=0; r<plen; r++)
190     {
191       output[fidx+r*fcount] = input[fidx*plen+r];
192     }
193   }
194 }
195
196 static
197 gboolean rs_correct_data(guint8 *deinterleaved, guint8 *output,
198  guint32 c_max, guint16 rsk, guint16 rsz _U_)
199 {
200   guint32 i, index_coded = 0, index_out = 0;
201   int err_corr;
202   for (i=0; i<c_max; i++)
203   {
204     memcpy(output+index_out, deinterleaved+index_coded, rsk);
205     index_coded += rsk;
206     memcpy(output+index_out+PFT_RS_N_MAX, deinterleaved+index_coded, PFT_RS_P);
207     index_coded += PFT_RS_P;
208     err_corr = eras_dec_rs(output+index_out, NULL, 0);
209     if (err_corr<0) {
210       return FALSE;
211     }
212     index_out += rsk;
213   }
214   return TRUE;
215 }
216
217 /* Don't attempt reassembly if we have a huge number of fragments. */
218 #define MAX_FRAGMENTS ((1 * 1024 * 1024) / sizeof(guint32))
219
220 static tvbuff_t *
221 dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
222   guint32 findex,
223   guint32 fcount,
224   guint16 seq,
225   gint offset,
226   guint16 plen,
227   gboolean fec _U_,
228   guint16 rsk,
229   guint16 rsz,
230   fragment_data *fd
231 )
232 {
233   guint16 decoded_size;
234   guint32 c_max;
235   guint32 rx_min;
236   gboolean first, last;
237   tvbuff_t *new_tvb=NULL;
238
239   if (fcount > MAX_FRAGMENTS) {
240     if (tree)
241       proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", fcount);
242     return NULL;
243   }
244
245   first = findex == 0;
246   last = fcount == (findex+1);
247   decoded_size = fcount*plen;
248   c_max = fcount*plen/(rsk+PFT_RS_P);  /* rounded down */
249   rx_min = c_max*rsk/plen;
250   if(rx_min*plen<c_max*rsk)
251     rx_min++;
252   if (fd)
253     new_tvb = process_reassembled_data (tvb, offset, pinfo,
254                                             "Reassembled Message",
255                                             fd, &dcp_frag_items,
256                                             NULL, tree);
257   else {
258     guint fragments=0;
259     guint32 *got;
260     fragment_data *fd;
261     fragment_data *fd_head;
262
263       if(tree)
264         proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
265         fcount, fragments, rx_min
266         );
267     got = ep_alloc(fcount*sizeof(guint32));
268
269         /* make a list of the findex (offset) numbers of the fragments we have */
270     fd = fragment_get(pinfo, seq, dcp_fragment_table);
271         for (fd_head = fd; fd_head != NULL; fd_head = fd_head->next) {
272       if(fd_head->data) {
273         got[fragments++] = fd_head->offset; /* this is the findex of the fragment */
274       }
275         }
276         /* put a sentinel at the end */
277     got[fragments++] = fcount;
278         /* have we got enough for Reed Solomon to try to correct ? */
279         if(fragments>=rx_min) { /* yes, in theory */
280       guint i,current_findex;
281       fragment_data *frag=NULL;
282       guint8 *dummy_data = (guint8*) ep_alloc0 (plen);
283       tvbuff_t *dummytvb = tvb_new_real_data(dummy_data, plen, plen);
284       /* try and decode with missing fragments */
285       if(tree)
286           proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
287           fcount, fragments, rx_min
288           );
289           /* fill the fragment table with empty fragments */
290           current_findex = 0;
291       for(i=0; i<fragments; i++) {
292             guint next_fragment_we_have = got[i];
293         for(; current_findex<next_fragment_we_have; current_findex++) {
294           frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq,
295             dcp_fragment_table, dcp_reassembled_table, current_findex, plen, (current_findex+1!=fcount));
296         }
297                 current_findex++; /* skip over the fragment we have */
298       }
299       if(frag)
300         new_tvb = process_reassembled_data (tvb, offset, pinfo,
301                                             "Reassembled Message",
302                                             frag, &dcp_frag_items,
303                                             NULL, tree);
304     }
305   }
306   if(new_tvb) {
307     gboolean decoded = TRUE;
308     tvbuff_t *dtvb = NULL;
309     const guint8 *input = tvb_get_ptr(new_tvb, 0, -1);
310     guint16 reassembled_size = tvb_length(new_tvb);
311     guint8 *deinterleaved = (guint8*) g_malloc (reassembled_size);
312     guint8 *output = (guint8*) g_malloc (decoded_size);
313     rs_deinterleave(input, deinterleaved, plen, fcount);
314
315     dtvb = tvb_new_real_data(deinterleaved, reassembled_size, reassembled_size);
316     tvb_set_child_real_data_tvbuff(tvb, dtvb);
317     add_new_data_source(pinfo, dtvb, "Deinterleaved");
318     tvb_set_free_cb(dtvb, g_free);
319
320     decoded = rs_correct_data(deinterleaved, output, c_max, rsk, rsz);
321     if(tree)
322         proto_tree_add_boolean (tree, hf_edcp_rs_ok, tvb, offset, 2, decoded);
323
324     new_tvb = tvb_new_real_data(output, decoded_size, decoded_size);
325     tvb_set_child_real_data_tvbuff(dtvb, new_tvb);
326     add_new_data_source(pinfo, new_tvb, "RS Error Corrected Data");
327     tvb_set_free_cb(new_tvb, g_free);
328   }
329   return new_tvb;
330 }
331
332
333 /** Handle a PFT packet which has the fragmentation header. This uses the
334  * standard wireshark methods for reassembling fragments. If FEC is used,
335  * the FEC is handled too. For the moment, all the fragments must be
336  * available but this could be improved.
337  *  \param[in,out] tvb The buffer containing the current fragment
338  *  \param[in,out] pinfo The packet info structure
339  *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
340  *  \param[in] findex the fragment count
341  *  \param[in] fcount the number of fragments
342  *  \param[in] seq the sequence number of the reassembled packet
343  *  \param[in] offset the offset into the tvb of the fragment
344  *  \param[in] plen the length of each fragment
345  *  \param[in] fec is fec used
346  *  \param[in] rsk the number of useful bytes in each chunk
347  *  \param[in] rsz the number of padding bytes in each chunk
348  */
349 static tvbuff_t *
350 dissect_pft_fragmented(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
351   guint32 findex,
352   guint32 fcount,
353   guint16 seq,
354   gint offset,
355   guint16 plen,
356   gboolean fec,
357   guint16 rsk,
358   guint16 rsz
359 )
360 {
361   gboolean first, last;
362   tvbuff_t *new_tvb=NULL;
363   fragment_data *frag_edcp = NULL;
364   pinfo->fragmented = TRUE;
365   first = findex == 0;
366   last = fcount == (findex+1);
367   frag_edcp = fragment_add_seq_check (
368      tvb, offset, pinfo,
369      seq,
370          dcp_fragment_table, dcp_reassembled_table,
371          findex,
372      plen,
373          !last);
374   if(fec) {
375     new_tvb = dissect_pft_fec_detailed(
376           tvb, pinfo, tree, findex, fcount, seq, offset, plen, fec, rsk, rsz, frag_edcp
377         );
378   } else {
379     new_tvb = process_reassembled_data (tvb, offset, pinfo,
380                                             "Reassembled Message",
381                                             frag_edcp, &dcp_frag_items,
382                                             NULL, tree);
383   }
384   if (check_col (pinfo->cinfo, COL_INFO)) {
385     if(new_tvb) {
386       col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembled)");
387     } else {
388       if(last) {
389         col_append_str (pinfo->cinfo, COL_INFO, " (Message Reassembly failure)");
390       } else {
391         col_append_fstr (pinfo->cinfo, COL_INFO, " (Message fragment %u)", findex);
392       }
393     }
394     if(first)
395       col_append_str (pinfo->cinfo, COL_INFO, " (first)");
396     if(last)
397       col_append_str (pinfo->cinfo, COL_INFO, " (last)");
398   }
399   return new_tvb;
400 }
401
402 /** Dissect a PFT packet. Details follow
403  *  here.
404  *  \param[in,out] tvb The buffer containing the packet
405  *  \param[in,out] pinfo The packet info structure
406  *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
407  */
408 static void
409 dissect_pft(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
410 {
411   guint16 plen;
412   gint offset = 0;
413   guint16 seq, payload_len, hcrc;
414   guint32 findex, fcount;
415   proto_tree *pft_tree = NULL;
416   proto_item *ti = NULL, *li = NULL;
417   tvbuff_t *next_tvb = NULL;
418   gboolean fec = FALSE;
419   guint16 rsk=0, rsz=0;
420
421   pinfo->current_proto = "DCP-PFT";
422   if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
423     col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-PFT");
424   }
425
426   if (tree) {                   /* we are being asked for details */
427     ti = proto_tree_add_item (tree, proto_pft, tvb, 0, -1, FALSE);
428     pft_tree = proto_item_add_subtree (ti, ett_pft);
429     proto_tree_add_item (pft_tree, hf_edcp_sync, tvb, offset, 2, FALSE);
430   }
431   offset += 2;
432   seq = tvb_get_ntohs (tvb, offset);
433   if (tree) {
434     proto_tree_add_item (pft_tree, hf_edcp_pseq, tvb, offset, 2, FALSE);
435   }
436   offset += 2;
437   findex = tvb_get_ntoh24 (tvb, offset);
438   if (tree) {
439     proto_tree_add_item (pft_tree, hf_edcp_findex, tvb, offset, 3, FALSE);
440   }
441   offset += 3;
442   fcount = tvb_get_ntoh24 (tvb, offset);
443   if (tree) {
444     proto_tree_add_item (pft_tree, hf_edcp_fcount, tvb, offset, 3, FALSE);
445   }
446   offset += 3;
447   plen = tvb_get_ntohs (tvb, offset);
448   payload_len = plen & 0x3fff;
449   if (tree) {
450     proto_tree_add_item (pft_tree, hf_edcp_fecflag, tvb, offset, 2, FALSE);
451     proto_tree_add_item (pft_tree, hf_edcp_addrflag, tvb, offset, 2, FALSE);
452     li = proto_tree_add_item (pft_tree, hf_edcp_plen, tvb, offset, 2, FALSE);
453   }
454   offset += 2;
455   if (plen & 0x8000) {
456     fec = TRUE;
457     rsk = tvb_get_guint8 (tvb, offset);
458     if (tree)
459           proto_tree_add_item (pft_tree, hf_edcp_rsk, tvb, offset, 1, FALSE);
460     offset += 1;
461     rsz = tvb_get_guint8 (tvb, offset);
462     if (tree)
463           proto_tree_add_item (pft_tree, hf_edcp_rsz, tvb, offset, 1, FALSE);
464     offset += 1;
465   }
466   if (plen & 0x4000) {
467     if (tree)
468       proto_tree_add_item (pft_tree, hf_edcp_source, tvb, offset, 2, FALSE);
469     offset += 2;
470     if (tree)
471           proto_tree_add_item (pft_tree, hf_edcp_dest, tvb, offset, 2, FALSE);
472     offset += 2;
473   }
474   if (tree) {
475     proto_item *ci = NULL;
476     guint header_len = offset+2;
477     const char *crc_buf = (const char *) tvb_get_ptr(tvb, 0, header_len);
478     unsigned long c = crc_drm(crc_buf, header_len, 16, 0x11021, 1);
479     ci = proto_tree_add_item (pft_tree, hf_edcp_hcrc, tvb, offset, 2, FALSE);
480     proto_item_append_text(ci, " (%s)", (c==0xe2f0)?"Ok":"bad");
481     proto_tree_add_boolean(pft_tree, hf_edcp_hcrc_ok, tvb, offset, 2, c==0xe2f0);
482   }
483   hcrc = tvb_get_ntohs (tvb, offset);
484   offset += 2;
485   if (fcount > 1) {             /* fragmented*/
486     gboolean save_fragmented = pinfo->fragmented;
487     guint16 real_len = tvb_length(tvb)-offset;
488     proto_tree_add_item (pft_tree, hf_edcp_pft_payload, tvb, offset, real_len, FALSE);
489     if(real_len != payload_len) {
490       if(li)
491         proto_item_append_text(li, " (length error (%d))", real_len);
492     }
493     next_tvb = dissect_pft_fragmented(tvb, pinfo, pft_tree,
494                                       findex, fcount, seq, offset, real_len,
495                                       fec, rsk, rsz
496                                       );
497     pinfo->fragmented = save_fragmented;
498   } else {
499     next_tvb = tvb_new_subset (tvb, offset, -1, -1);
500   }
501   if(next_tvb) {
502     dissect_af(next_tvb, pinfo, tree);
503   }
504 }
505
506 /** Dissect an AF Packet. Parse an AF packet, checking the CRC if the CRC valid
507  * flag is set and calling any registered sub dissectors on the payload type.
508  * Currently only a payload type 'T' is defined which is the tag packet layer.
509  * If any others are defined then they can register themselves.
510  *  \param[in,out] tvb The buffer containing the packet
511  *  \param[in,out] pinfo The packet info structure
512  *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
513  */
514 static void
515 dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
516 {
517   gint offset = 0;
518   proto_item *ti = NULL;
519   proto_item *li = NULL;
520   proto_item *ci = NULL;
521   proto_tree *af_tree = NULL;
522   guint8 ver, pt;
523   guint32 payload_len;
524   tvbuff_t *next_tvb = NULL;
525
526   pinfo->current_proto = "DCP-AF";
527   if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
528     col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-AF");
529   }
530
531   if (tree) {                   /* we are being asked for details */
532     ti = proto_tree_add_item (tree, proto_af, tvb, 0, -1, FALSE);
533     af_tree = proto_item_add_subtree (ti, ett_af);
534     proto_tree_add_item (af_tree, hf_edcp_sync, tvb, offset, 2, FALSE);
535   }
536   offset += 2;
537   payload_len = tvb_get_ntohl(tvb, offset);
538   if (tree) {
539     guint32 real_payload_len = tvb_length(tvb)-12;
540     li = proto_tree_add_item (af_tree, hf_edcp_len, tvb, offset, 4, FALSE);
541     if(real_payload_len < payload_len) {
542       proto_item_append_text (li, " (wrong len claims %d is %d)",
543       payload_len, real_payload_len
544       );
545     } else if(real_payload_len > payload_len) {
546       proto_item_append_text (li, " (%d bytes in packet after end of AF frame)",
547       real_payload_len-payload_len
548       );
549     }
550   }
551   offset += 4;
552   if (tree)
553     proto_tree_add_item (af_tree, hf_edcp_seq, tvb, offset, 2, FALSE);
554   offset += 2;
555   ver = tvb_get_guint8 (tvb, offset);
556   if (tree) {
557     proto_tree_add_item (af_tree, hf_edcp_crcflag, tvb, offset, 1, FALSE);
558     proto_tree_add_item (af_tree, hf_edcp_maj, tvb, offset, 1, FALSE);
559     proto_tree_add_item (af_tree, hf_edcp_min, tvb, offset, 1, FALSE);
560   }
561   offset += 1;
562   pt = tvb_get_guint8 (tvb, offset);
563   if (tree)
564     proto_tree_add_item (af_tree, hf_edcp_pt, tvb, offset, 1, FALSE);
565   offset += 1;
566   next_tvb = tvb_new_subset (tvb, offset, payload_len, -1);
567   offset += payload_len;
568   if (tree)
569     ci = proto_tree_add_item (af_tree, hf_edcp_crc, tvb, offset, 2, FALSE);
570   if (ver & 0x80) { /* crc valid */
571     guint len = offset+2;
572     const char *crc_buf = (const char *) tvb_get_ptr(tvb, 0, len);
573     unsigned long c = crc_drm(crc_buf, len, 16, 0x11021, 1);
574     if (tree) {
575           proto_item_append_text(ci, " (%s)", (c==0xe2f0)?"Ok":"bad");
576       proto_tree_add_boolean(af_tree, hf_edcp_crc_ok, tvb, offset, 2, c==0xe2f0);
577     }
578   }
579   offset += 2;
580   dissector_try_port(af_dissector_table, pt, next_tvb, pinfo, tree);
581 }
582
583 /** Dissect the Tag Packet Layer.
584  *  Split the AF packet into its tag items. Each tag item has a 4 character
585  *  tag, a length in bits and a value. The *ptr tag is dissected in the routine.
586  *  All other tags are listed and may be handled by other dissectors.
587  *  Child dissectors are tied to the parent tree, not to this tree, so that
588  *  they appear at the same level as DCP.
589  *  \param[in,out] tvb The buffer containing the packet
590  *  \param[in,out] pinfo The packet info structure
591  *  \param[in,out] tree The structure containing the details which will be displayed, filtered, etc.
592  */
593 static void
594 dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
595 {
596   proto_tree *tpl_tree = NULL;
597   guint offset=0;
598   char *prot=NULL;
599   guint16 maj, min;
600
601   pinfo->current_proto = "DCP-TPL";
602   if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
603     col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-TPL");
604   }
605
606   if(tree) {
607     proto_item *ti = NULL;
608     ti = proto_tree_add_item (tree, proto_tpl, tvb, 0, -1, FALSE);
609     tpl_tree = proto_item_add_subtree (ti, ett_tpl);
610   }
611   while(offset<tvb_length(tvb)) {
612     guint32 bits;
613     guint32 bytes;
614     char *tag = (char*)tvb_get_ephemeral_string (tvb, offset, 4); offset += 4;
615     bits = tvb_get_ntohl(tvb, offset); offset += 4;
616     bytes = bits / 8;
617     if(bits % 8)
618       bytes++;
619     if(tree) {
620       proto_item *i = NULL;
621       const guint8 *p = tvb_get_ptr(tvb, offset, bytes);
622       if(strcmp(tag, "*ptr")==0) {
623         prot = (char*)tvb_get_ephemeral_string (tvb, offset, 4);
624         maj = tvb_get_ntohs(tvb, offset+4);
625         min = tvb_get_ntohs(tvb, offset+6);
626         i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
627               offset-8, bytes+8, p, "%s %s rev %d.%d", tag, prot, maj, min);
628       } else {
629         i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
630               offset-8, bytes+8, p, "%s (%u bits)", tag, bits);
631       }
632     }
633     offset += bytes;
634   }
635   if(prot) {  /* prot is non-NULL only if we have our tree. */
636     dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, tree->parent);
637   }
638 }
639
640 void
641 proto_reg_handoff_dcp_etsi (void)
642 {
643   static int Initialized = FALSE;
644
645   if (!Initialized) {
646         af_handle = create_dissector_handle(dissect_af, proto_af);
647         pft_handle = create_dissector_handle(dissect_pft, proto_pft);
648         tpl_handle = create_dissector_handle(dissect_tpl, proto_tpl);
649         heur_dissector_add("udp", dissect_dcp_etsi, proto_dcp_etsi);
650      dissector_add_string("dcp-etsi.sync", "AF", af_handle);
651     dissector_add_string("dcp-etsi.sync", "PF", pft_handle);
652     /* if there are ever other payload types ...*/
653     dissector_add("dcp-af.pt", 'T', tpl_handle);
654   }
655 }
656
657 void
658 proto_register_dcp_etsi (void)
659 {
660   module_t *dcp_module;
661   static hf_register_info hf_edcp[] = {
662     {&hf_edcp_sync,
663      {"sync", "dcp-etsi.sync",
664       FT_STRING, BASE_NONE, NULL, 0,
665       "AF or PF", HFILL}
666      }
667     };
668   static hf_register_info hf_af[] = {
669     {&hf_edcp_len,
670      {"length", "dcp-af.len",
671       FT_UINT32, BASE_DEC, NULL, 0,
672       "length in bytes of the payload", HFILL}
673      },
674     {&hf_edcp_seq,
675      {"frame count", "dcp-af.seq",
676       FT_UINT16, BASE_DEC, NULL, 0,
677       "Logical Frame Number", HFILL}
678      },
679     {&hf_edcp_crcflag,
680      {"crc flag", "dcp-af.crcflag",
681       FT_BOOLEAN, BASE_NONE, NULL, 0x80,
682       "Frame is protected by CRC", HFILL}
683      },
684     {&hf_edcp_maj,
685      {"Major Revision", "dcp-af.maj",
686       FT_UINT8, BASE_DEC, NULL, 0x70,
687       "Major Protocol Revision", HFILL}
688      },
689     {&hf_edcp_min,
690      {"Minor Revision", "dcp-af.min",
691       FT_UINT8, BASE_DEC, NULL, 0x0f,
692       "Minor Protocol Revision", HFILL}
693      },
694     {&hf_edcp_pt,
695      {"Payload Type", "dcp-af.pt",
696       FT_STRING, BASE_NONE, NULL, 0,
697       "T means Tag Packets, all other values reserved", HFILL}
698      },
699     {&hf_edcp_crc,
700      {"CRC", "dcp-af.crc",
701       FT_UINT16, BASE_HEX, NULL, 0,
702       "CRC", HFILL}
703      },
704     {&hf_edcp_crc_ok,
705      {"CRC OK", "dcp-af.crc_ok",
706       FT_BOOLEAN, BASE_NONE, NULL, 0,
707       "AF CRC OK", HFILL}
708      }
709     };
710
711   static hf_register_info hf_pft[] = {
712     {&hf_edcp_pft_pt,
713      {"Sub-protocol", "dcp-pft.pt",
714       FT_UINT8, BASE_DEC, NULL, 0,
715       "Always AF", HFILL}
716      },
717     {&hf_edcp_pseq,
718      {"Sequence No", "dcp-pft.seq",
719       FT_UINT16, BASE_DEC, NULL, 0,
720       "PFT Sequence No", HFILL}
721      },
722     {&hf_edcp_findex,
723      {"Fragment Index", "dcp-pft.findex",
724       FT_UINT24, BASE_DEC, NULL, 0,
725       "Index of the fragment within one AF Packet", HFILL}
726      },
727     {&hf_edcp_fcount,
728      {"Fragment Count", "dcp-pft.fcount",
729       FT_UINT24, BASE_DEC, NULL, 0,
730       "Number of fragments produced from this AF Packet", HFILL}
731      },
732     {&hf_edcp_fecflag,
733      {"FEC", "dcp-pft.fec",
734       FT_BOOLEAN, BASE_NONE, NULL, 0x8000,
735       "When set the optional RS header is present", HFILL}
736      },
737     {&hf_edcp_addrflag,
738      {"Addr", "dcp-pft.addr",
739       FT_BOOLEAN, BASE_NONE, NULL, 0x4000,
740       "When set the optional transport header is present", HFILL}
741      },
742     {&hf_edcp_plen,
743      {"fragment length", "dcp-pft.len",
744       FT_UINT16, BASE_DEC, NULL, 0x3fff,
745       "length in bytes of the payload of this fragment", HFILL}
746      },
747     {&hf_edcp_rsk,
748      {"RSk", "dcp-pft.rsk",
749       FT_UINT8, BASE_DEC, NULL, 0,
750       "The length of the Reed Solomon data word", HFILL}
751      },
752     {&hf_edcp_rsz,
753      {"RSz", "dcp-pft.rsz",
754       FT_UINT8, BASE_DEC, NULL, 0,
755       "The number of padding bytes in the last Reed Solomon block", HFILL}
756      },
757     {&hf_edcp_source,
758      {"source addr", "dcp-pft.source",
759       FT_UINT16, BASE_DEC, NULL, 0,
760       "PFT source identifier", HFILL}
761      },
762     {&hf_edcp_dest,
763      {"dest addr", "dcp-pft.dest",
764       FT_UINT16, BASE_DEC, NULL, 0,
765       "PFT destination identifier", HFILL}
766      },
767     {&hf_edcp_hcrc,
768      {"header CRC", "dcp-pft.crc",
769       FT_UINT16, BASE_HEX, NULL, 0,
770       "PFT Header CRC", HFILL}
771      },
772     {&hf_edcp_hcrc_ok,
773      {"PFT CRC OK", "dcp-pft.crc_ok",
774       FT_BOOLEAN, BASE_NONE, NULL, 0,
775       "PFT Header CRC OK", HFILL}
776      },
777     {&hf_edcp_fragments,
778      {"Message fragments", "dcp-pft.fragments",
779       FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL}},
780     {&hf_edcp_fragment,
781      {"Message fragment", "dcp-pft.fragment",
782       FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
783     {&hf_edcp_fragment_overlap,
784      {"Message fragment overlap", "dcp-pft.fragment.overlap",
785       FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
786     {&hf_edcp_fragment_overlap_conflicts,
787      {"Message fragment overlapping with conflicting data",
788       "dcp-pft.fragment.overlap.conflicts",
789       FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
790     {&hf_edcp_fragment_multiple_tails,
791      {"Message has multiple tail fragments",
792       "dcp-pft.fragment.multiple_tails",
793       FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
794     {&hf_edcp_fragment_too_long_fragment,
795      {"Message fragment too long", "dcp-pft.fragment.too_long_fragment",
796       FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL}},
797     {&hf_edcp_fragment_error,
798      {"Message defragmentation error", "dcp-pft.fragment.error",
799       FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
800     {&hf_edcp_reassembled_in,
801      {"Reassembled in", "dcp-pft.reassembled.in",
802       FT_FRAMENUM, BASE_NONE, NULL, 0x00, NULL, HFILL}},
803     {&hf_edcp_c_max,
804      {"C max", "dcp-pft.cmax",
805       FT_UINT16, BASE_DEC, NULL, 0,
806       "Maximum number of RS chunks sent", HFILL}
807      },
808     {&hf_edcp_rx_min,
809      {"Rx min", "dcp-pft.rxmin",
810       FT_UINT16, BASE_DEC, NULL, 0,
811       "Minimum number of fragments needed for RS decode", HFILL}
812      },
813     {&hf_edcp_rs_corrected,
814      {"RS Symbols Corrected", "dcp-pft.rs_corrected",
815       FT_INT16, BASE_DEC, NULL, 0,
816       "Number of symbols corrected by RS decode or -1 for failure", HFILL}
817      },
818     {&hf_edcp_rs_ok,
819      {"RS decode OK", "dcp-pft.rs_ok",
820       FT_BOOLEAN, BASE_NONE, NULL, 0,
821       "successfully decoded RS blocks", HFILL}
822      },
823     {&hf_edcp_pft_payload,
824      {"payload", "dcp-pft.payload",
825       FT_BYTES, BASE_HEX, NULL, 0,
826       "PFT Payload", HFILL}
827     }
828   };
829
830   static hf_register_info hf_tpl[] = {
831     {&hf_tpl_tlv,
832      {"tag", "dcp-tpl.tlv",
833       FT_BYTES, BASE_HEX, NULL, 0,
834       "Tag Packet", HFILL}
835      },
836     {&hf_tpl_ptr,
837      {"Type", "dcp-tpl.ptr",
838       FT_STRING, BASE_NONE, NULL, 0,
839       "Protocol Type & Revision", HFILL}
840      }
841     };
842
843 /* Setup protocol subtree array */
844   static gint *ett[] = {
845     &ett_edcp,
846     &ett_af,
847     &ett_pft,
848     &ett_tpl,
849     &ett_edcp_fragment,
850     &ett_edcp_fragments
851   };
852
853   if (proto_dcp_etsi == -1) {
854     proto_dcp_etsi = proto_register_protocol ("ETSI Distribution & Communication Protocol (for DRM)",   /* name */
855                                          "DCP (ETSI)",  /* short name */
856                                          "dcp-etsi"     /* abbrev */
857       );
858     proto_af = proto_register_protocol ("DCP Application Framing Layer", "DCP-AF", "dcp-af");
859     proto_pft = proto_register_protocol ("DCP Protection, Fragmentation & Transport Layer", "DCP-PFT", "dcp-pft");
860     proto_tpl = proto_register_protocol ("DCP Tag Packet Layer", "DCP-TPL", "dcp-tpl");
861
862
863   }
864   dcp_module = prefs_register_protocol (proto_dcp_etsi, proto_reg_handoff_dcp_etsi);
865   proto_register_field_array (proto_dcp_etsi, hf_edcp, array_length (hf_edcp));
866   proto_register_field_array (proto_af, hf_af, array_length (hf_af));
867   proto_register_field_array (proto_pft, hf_pft, array_length (hf_pft));
868   proto_register_field_array (proto_tpl, hf_tpl, array_length (hf_tpl));
869   proto_register_subtree_array (ett, array_length (ett));
870
871   /* subdissector code */
872   dcp_dissector_table = register_dissector_table("dcp-etsi.sync",
873             "DCP Sync", FT_STRING, BASE_NONE);
874   af_dissector_table = register_dissector_table("dcp-af.pt",
875             "AF Payload Type", FT_UINT8, BASE_DEC);
876
877   tpl_dissector_table = register_dissector_table("dcp-tpl.ptr",
878             "AF Payload Type", FT_STRING, BASE_NONE);
879
880   register_init_routine(dcp_init_protocol);
881
882 }
883
884