Minor cleanup related to proto_register & proto_reg_handoff
[obnox/wireshark/wip.git] / epan / dissectors / packet-dcp-etsi.c
index 42e475f75fc4eb867b709b322f21f6b94cedf75d..d2b6c8fac03a34379cc9c21422aefc4e9885137c 100644 (file)
@@ -1,8 +1,8 @@
 /* packet-dcp-etsi.c
- * Routines for ETSI Distribution & Communication Protocol 
- * Copyright 2006, British Broadcasting Corporation 
+ * Routines for ETSI Distribution & Communication Protocol
+ * Copyright 2006, British Broadcasting Corporation
  *
- * $Id:$
+ * $Id$
  *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
 
 #include <gmodule.h>
 #include <epan/packet.h>
-#include <epan/prefs.h>
 #include <epan/reassemble.h>
 #include <epan/crcdrm.h>
 #include <epan/reedsolomon.h>
+#include <epan/emem.h>
 #include <string.h>
 
 /* forward reference */
@@ -53,9 +53,6 @@ static int proto_dcp_etsi = -1;
 static int proto_af = -1;
 static int proto_pft = -1;
 static int proto_tpl = -1;
-static dissector_handle_t af_handle;
-static dissector_handle_t pft_handle;
-static dissector_handle_t tpl_handle;
 static int hf_edcp_sync = -1;
 static int hf_edcp_len = -1;
 static int hf_edcp_seq = -1;
@@ -148,12 +145,12 @@ dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 {
   guint8 *sync;
   proto_tree *dcp_tree = NULL;
-  sync = tvb_get_string (tvb, 0, 2);
+  sync = tvb_get_ephemeral_string (tvb, 0, 2);
   if((sync[0]!='A' && sync[0]!='P') || sync[1]!='F')
     return FALSE;
-  
+
   pinfo->current_proto = "DCP (ETSI)";
-  
+
   /* Clear out stuff in the info column */
   if (check_col (pinfo->cinfo, COL_INFO)) {
     col_clear (pinfo->cinfo, COL_INFO);
@@ -170,7 +167,6 @@ dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
   }
 
   dissector_try_string(dcp_dissector_table, (char*)sync, tvb, pinfo, dcp_tree);
-  g_free (sync);
   return TRUE;
 }
 
@@ -179,7 +175,7 @@ dissect_dcp_etsi (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 #define PFT_RS_P (PFT_RS_K - PFT_RS_N_MAX)
 
 
-static 
+static
 void rs_deinterleave(const guint8 *input, guint8 *output, guint16 plen, guint32 fcount)
 {
   guint fidx;
@@ -193,9 +189,9 @@ void rs_deinterleave(const guint8 *input, guint8 *output, guint16 plen, guint32
   }
 }
 
-static 
-gboolean rs_correct_data(guint8 *deinterleaved, guint8 *output, 
- guint32 c_max, guint16 rsk, guint16 rsz)
+static
+gboolean rs_correct_data(guint8 *deinterleaved, guint8 *output,
+ guint32 c_max, guint16 rsk, guint16 rsz _U_)
 {
   guint32 i, index_coded = 0, index_out = 0;
   int err_corr;
@@ -214,7 +210,8 @@ gboolean rs_correct_data(guint8 *deinterleaved, guint8 *output,
   return TRUE;
 }
 
-
+/* Don't attempt reassembly if we have a huge number of fragments. */
+#define MAX_FRAGMENTS ((1 * 1024 * 1024) / sizeof(guint32))
 
 static tvbuff_t *
 dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
@@ -223,18 +220,24 @@ dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
   guint16 seq,
   gint offset,
   guint16 plen,
-  gboolean fec,
+  gboolean fec _U_,
   guint16 rsk,
   guint16 rsz,
-  fragment_data *fd
+  fragment_data *fdx
 )
 {
   guint16 decoded_size;
   guint32 c_max;
   guint32 rx_min;
-  gboolean first, last, decoded = TRUE;
+  gboolean first, last;
   tvbuff_t *new_tvb=NULL;
 
+  if (fcount > MAX_FRAGMENTS) {
+    if (tree)
+      proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", fcount);
+    return NULL;
+  }
+
   first = findex == 0;
   last = fcount == (findex+1);
   decoded_size = fcount*plen;
@@ -242,49 +245,57 @@ dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
   rx_min = c_max*rsk/plen;
   if(rx_min*plen<c_max*rsk)
     rx_min++;
-  if (fd)
+  if (fdx)
     new_tvb = process_reassembled_data (tvb, offset, pinfo,
                                            "Reassembled Message",
-                                           fd, &dcp_frag_items,
+                                           fdx, &dcp_frag_items,
                                            NULL, tree);
   else {
     guint fragments=0;
-    guint32 *got = g_malloc(fcount*sizeof(guint32));
-
-    fragment_data *fd = fragment_get(pinfo, seq, dcp_fragment_table);
+    guint32 *got;
+    fragment_data *fd;
     fragment_data *fd_head;
+
+      if(tree)
+        proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
+        fcount, fragments, rx_min
+        );
+    got = ep_alloc(fcount*sizeof(guint32));
+
+       /* make a list of the findex (offset) numbers of the fragments we have */
+    fd = fragment_get(pinfo, seq, dcp_fragment_table);
        for (fd_head = fd; fd_head != NULL; fd_head = fd_head->next) {
       if(fd_head->data) {
-        got[fragments] = fd_head->offset;
-        fragments++;
+        got[fragments++] = fd_head->offset; /* this is the findex of the fragment */
       }
        }
-       if(fragments>=rx_min) {
-      guint i,j;
+       /* put a sentinel at the end */
+    got[fragments++] = fcount;
+       /* have we got enough for Reed Solomon to try to correct ? */
+       if(fragments>=rx_min) { /* yes, in theory */
+      guint i,current_findex;
       fragment_data *frag=NULL;
-      guint8 *dummy_data = (guint8*) g_malloc (plen);
+      guint8 *dummy_data = (guint8*) ep_alloc0 (plen);
       tvbuff_t *dummytvb = tvb_new_real_data(dummy_data, plen, plen);
       /* try and decode with missing fragments */
       if(tree)
           proto_tree_add_text (tree, tvb, 0, -1, "want %d, got %d need %d",
           fcount, fragments, rx_min
           );
-      memset(dummy_data, 0, plen);
-      for(i=0,j=0; i<fragments; i++,j++) {
-        while(j<got[i]) {
-          frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq,      
-            dcp_fragment_table, dcp_reassembled_table, j, plen, (j+1!=fcount));
-         if(tree) {
-              proto_tree_add_text (tree, tvb, 0, -1, "missing %d", j);
-              if(frag) {
-                proto_tree_add_text (tree, tvb, 0, -1, "fragment %d was what we needed", j);
-                break;
-              } else {
-                proto_tree_add_text (tree, tvb, 0, -1, "added %d but still not reassembled", j);
-              }
-          }
-          j++;
+         /* fill the fragment table with empty fragments */
+         current_findex = 0;
+      for(i=0; i<fragments; i++) {
+           guint next_fragment_we_have = got[i];
+            if (next_fragment_we_have > MAX_FRAGMENTS) {
+              if (tree)
+                proto_tree_add_text(tree, tvb , 0, -1, "[Reassembly of %d fragments not attempted]", next_fragment_we_have);
+                return NULL;
+            }
+        for(; current_findex<next_fragment_we_have; current_findex++) {
+          frag = fragment_add_seq_check (dummytvb, 0, pinfo, seq,
+            dcp_fragment_table, dcp_reassembled_table, current_findex, plen, (current_findex+1!=fcount));
         }
+               current_findex++; /* skip over the fragment we have */
       }
       if(frag)
         new_tvb = process_reassembled_data (tvb, offset, pinfo,
@@ -292,9 +303,9 @@ dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
                                            frag, &dcp_frag_items,
                                            NULL, tree);
     }
-    g_free(got);
   }
   if(new_tvb) {
+    gboolean decoded = TRUE;
     tvbuff_t *dtvb = NULL;
     const guint8 *input = tvb_get_ptr(new_tvb, 0, -1);
     guint16 reassembled_size = tvb_length(new_tvb);
@@ -321,7 +332,7 @@ dissect_pft_fec_detailed(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
 
 
 /** Handle a PFT packet which has the fragmentation header. This uses the
- * standard ethereal methods for reassembling fragments. If FEC is used,
+ * standard wireshark methods for reassembling fragments. If FEC is used,
  * the FEC is handled too. For the moment, all the fragments must be
  * available but this could be improved.
  *  \param[in,out] tvb The buffer containing the current fragment
@@ -356,10 +367,10 @@ dissect_pft_fragmented(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
   last = fcount == (findex+1);
   frag_edcp = fragment_add_seq_check (
      tvb, offset, pinfo,
-     seq,      
-        dcp_fragment_table, dcp_reassembled_table,     
+     seq,
+        dcp_fragment_table, dcp_reassembled_table,
         findex,
-     plen,     
+     plen,
         !last);
   if(fec) {
     new_tvb = dissect_pft_fec_detailed(
@@ -464,7 +475,7 @@ dissect_pft(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
   if (tree) {
     proto_item *ci = NULL;
     guint header_len = offset+2;
-    const guint8 *crc_buf = tvb_get_ptr(tvb, 0, header_len);
+    const char *crc_buf = (const char *) tvb_get_ptr(tvb, 0, header_len);
     unsigned long c = crc_drm(crc_buf, header_len, 16, 0x11021, 1);
     ci = proto_tree_add_item (pft_tree, hf_edcp_hcrc, tvb, offset, 2, FALSE);
     proto_item_append_text(ci, " (%s)", (c==0xe2f0)?"Ok":"bad");
@@ -480,7 +491,7 @@ dissect_pft(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
       if(li)
         proto_item_append_text(li, " (length error (%d))", real_len);
     }
-    next_tvb = dissect_pft_fragmented(tvb, pinfo, pft_tree, 
+    next_tvb = dissect_pft_fragmented(tvb, pinfo, pft_tree,
                                       findex, fcount, seq, offset, real_len,
                                       fec, rsk, rsz
                                       );
@@ -559,7 +570,7 @@ dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
     ci = proto_tree_add_item (af_tree, hf_edcp_crc, tvb, offset, 2, FALSE);
   if (ver & 0x80) { /* crc valid */
     guint len = offset+2;
-    const guint8 *crc_buf = tvb_get_ptr(tvb, 0, len);
+    const char *crc_buf = (const char *) tvb_get_ptr(tvb, 0, len);
     unsigned long c = crc_drm(crc_buf, len, 16, 0x11021, 1);
     if (tree) {
          proto_item_append_text(ci, " (%s)", (c==0xe2f0)?"Ok":"bad");
@@ -570,7 +581,7 @@ dissect_af (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
   dissector_try_port(af_dissector_table, pt, next_tvb, pinfo, tree);
 }
 
-/** Dissect the Tag Packet Layer. 
+/** Dissect the Tag Packet Layer.
  *  Split the AF packet into its tag items. Each tag item has a 4 character
  *  tag, a length in bits and a value. The *ptr tag is dissected in the routine.
  *  All other tags are listed and may be handled by other dissectors.
@@ -585,73 +596,68 @@ dissect_tpl(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
 {
   proto_tree *tpl_tree = NULL;
   guint offset=0;
-  char *prot=NULL;  
+  char *prot=NULL;
   guint16 maj, min;
 
   pinfo->current_proto = "DCP-TPL";
   if (check_col (pinfo->cinfo, COL_PROTOCOL)) {
     col_set_str (pinfo->cinfo, COL_PROTOCOL, "DCP-TPL");
   }
-  
+
   if(tree) {
     proto_item *ti = NULL;
     ti = proto_tree_add_item (tree, proto_tpl, tvb, 0, -1, FALSE);
     tpl_tree = proto_item_add_subtree (ti, ett_tpl);
   }
   while(offset<tvb_length(tvb)) {
-         guint32 bits;
-         guint32 bytes;
-         char *tag = (char*)tvb_get_string (tvb, offset, 4); offset += 4;
-         bits = tvb_get_ntohl(tvb, offset); offset += 4;
-         bytes = bits / 8;
-         if(bits % 8)
-                 bytes++;
-         if(tree) {
+    guint32 bits;
+    guint32 bytes;
+    char *tag = (char*)tvb_get_ephemeral_string (tvb, offset, 4); offset += 4;
+    bits = tvb_get_ntohl(tvb, offset); offset += 4;
+    bytes = bits / 8;
+    if(bits % 8)
+      bytes++;
+    if(tree) {
       proto_item *i = NULL;
       const guint8 *p = tvb_get_ptr(tvb, offset, bytes);
       if(strcmp(tag, "*ptr")==0) {
-        prot = (char*)tvb_get_string (tvb, offset, 4);
+        prot = (char*)tvb_get_ephemeral_string (tvb, offset, 4);
         maj = tvb_get_ntohs(tvb, offset+4);
         min = tvb_get_ntohs(tvb, offset+6);
-        i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb, 
-              offset-8, bytes+8, p, "%s %s rev %d.%d", tag, prot, maj, min);        
+        i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
+              offset-8, bytes+8, p, "%s %s rev %d.%d", tag, prot, maj, min);
       } else {
-        i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb, 
+        i = proto_tree_add_bytes_format(tpl_tree, hf_tpl_tlv, tvb,
               offset-8, bytes+8, p, "%s (%u bits)", tag, bits);
       }
     }
     offset += bytes;
   }
-  if(prot) {
-    if(tree) {
-      dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, tree->parent);  
-    } else {
-      dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, NULL);  
-    }
+  if(prot) {  /* prot is non-NULL only if we have our tree. */
+    dissector_try_string(tpl_dissector_table, prot, tvb, pinfo, tree->parent);
   }
 }
 
 void
 proto_reg_handoff_dcp_etsi (void)
 {
-  static int Initialized = FALSE;
-
-  if (!Initialized) {
-       af_handle = create_dissector_handle(dissect_af, proto_af);
-       pft_handle = create_dissector_handle(dissect_pft, proto_pft);
-       tpl_handle = create_dissector_handle(dissect_tpl, proto_tpl);
-       heur_dissector_add("udp", dissect_dcp_etsi, proto_dcp_etsi);
-     dissector_add_string("dcp-etsi.sync", "AF", af_handle);
-    dissector_add_string("dcp-etsi.sync", "PF", pft_handle);
-    /* if there are ever other payload types ...*/
-    dissector_add("dcp-af.pt", 'T', tpl_handle);
-  }
+  dissector_handle_t af_handle;
+  dissector_handle_t pft_handle;
+  dissector_handle_t tpl_handle;
+
+  af_handle = create_dissector_handle(dissect_af, proto_af);
+  pft_handle = create_dissector_handle(dissect_pft, proto_pft);
+  tpl_handle = create_dissector_handle(dissect_tpl, proto_tpl);
+  heur_dissector_add("udp", dissect_dcp_etsi, proto_dcp_etsi);
+  dissector_add_string("dcp-etsi.sync", "AF", af_handle);
+  dissector_add_string("dcp-etsi.sync", "PF", pft_handle);
+  /* if there are ever other payload types ...*/
+  dissector_add("dcp-af.pt", 'T', tpl_handle);
 }
 
 void
 proto_register_dcp_etsi (void)
 {
-  module_t *dcp_module;
   static hf_register_info hf_edcp[] = {
     {&hf_edcp_sync,
      {"sync", "dcp-etsi.sync",
@@ -844,18 +850,14 @@ proto_register_dcp_etsi (void)
     &ett_edcp_fragments
   };
 
-  if (proto_dcp_etsi == -1) {
-    proto_dcp_etsi = proto_register_protocol ("ETSI Distribution & Communication Protocol (for DRM)",  /* name */
-                                        "DCP (ETSI)",  /* short name */
-                                        "dcp-etsi"     /* abbrev */
-      );
-    proto_af = proto_register_protocol ("DCP Application Framing Layer", "DCP-AF", "dcp-af");
-    proto_pft = proto_register_protocol ("DCP Protection, Fragmentation & Transport Layer", "DCP-PFT", "dcp-pft");
-    proto_tpl = proto_register_protocol ("DCP Tag Packet Layer", "DCP-TPL", "dcp-tpl");
+  proto_dcp_etsi = proto_register_protocol ("ETSI Distribution & Communication Protocol (for DRM)",    /* name */
+                                            "DCP (ETSI)",      /* short name */
+                                            "dcp-etsi" /* abbrev */
+    );
+  proto_af = proto_register_protocol ("DCP Application Framing Layer", "DCP-AF", "dcp-af");
+  proto_pft = proto_register_protocol ("DCP Protection, Fragmentation & Transport Layer", "DCP-PFT", "dcp-pft");
+  proto_tpl = proto_register_protocol ("DCP Tag Packet Layer", "DCP-TPL", "dcp-tpl");
 
-
-  }
-  dcp_module = prefs_register_protocol (proto_dcp_etsi, proto_reg_handoff_dcp_etsi);
   proto_register_field_array (proto_dcp_etsi, hf_edcp, array_length (hf_edcp));
   proto_register_field_array (proto_af, hf_af, array_length (hf_af));
   proto_register_field_array (proto_pft, hf_pft, array_length (hf_pft));