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