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