- Map gre -> IP
[metze/wireshark/wip.git] / wiretap / catapult_dct2000.c
index 7a39dbeec000ba2f742b35a08e7b3a21654e9156..c090804c8791340350fcbefc8d44d9ce1200940c 100644 (file)
 #define MAX_PROTOCOL_NAME          64
 #define MAX_PORT_DIGITS            2
 #define MAX_VARIANT_DIGITS         32
+#define MAX_OUTHDR_NAME            64
 #define AAL_HEADER_CHARS           12
 
 /* TODO:
+   - support for FP over AAL0
+   - support for IuR interface FP
    - support for x.25?
 */
 
@@ -60,7 +63,7 @@ typedef enum packet_direction_t
 typedef struct
 {
     gchar *before_time;
-    gchar *after_time;
+    gchar *after_time; /* If NULL assume " l " */
 } line_prefix_info_t;
 
 /*******************************************************************/
@@ -79,7 +82,7 @@ typedef struct dct2000_file_externals
        Records (file offset -> pre-data-prefix-string)
        N.B. This is only needed for dumping
     */
-    GHashTable *line_header_prefixes_table;
+    GHashTable *packet_prefix_table;
 } dct2000_file_externals_t;
 
 /* This global table maps wtap -> file_external structs */
@@ -105,19 +108,14 @@ static guint8 context_port;
 /* The DCT2000 protocol name of the packet, plus variant number */
 static gchar protocol_name[MAX_PROTOCOL_NAME+1];
 static gchar variant_name[MAX_VARIANT_DIGITS+1];
+static gchar outhdr_name[MAX_OUTHDR_NAME+1];
 
 
-/*************************************************/
-/* Preference state (shared with stub protocol). */
-/* Set to FALSE to get better use out of other   */
-/* wiretap applications (mergecap, editcap)      */
-gboolean catapult_dct2000_board_ports_only = FALSE;
-
 /************************************************************/
 /* Functions called from wiretap                            */
 static gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info,
-                                      long *data_offset);
-static gboolean catapult_dct2000_seek_read(wtap *wth, long seek_off,
+                                      gint64 *data_offset);
+static gboolean catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
                                            union wtap_pseudo_header *pseudo_header,
                                            guchar *pd, int length,
                                            int *err, gchar **err_info);
@@ -131,14 +129,13 @@ static gboolean catapult_dct2000_dump_close(wtap_dumper *wdh, int *err);
 
 /************************************************************/
 /* Private helper functions                                 */
-static gboolean read_new_line(FILE_T fh, long *offset, gint *length);
+static gboolean read_new_line(FILE_T fh, gint64 *offset, gint *length);
 static gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
                            long *before_time_offset, long *after_time_offset,
                            long *data_offset,
                            gint *data_chars,
                            packet_direction_t *direction,
-                           int *encap,
-                           gboolean seek_read);
+                           int *encap);
 static int write_stub_header(guchar *frame_buffer, char *timestamp_string,
                       packet_direction_t direction, int encap);
 static guchar hex_from_char(gchar c);
@@ -146,20 +143,21 @@ static gchar char_from_hex(guchar hex);
 
 static void set_pseudo_header_info(wtap *wth,
                                    int pkt_encap,
-                                   long file_offset,
+                                   gint64 file_offset,
                                    union wtap_pseudo_header *pseudo_header,
-                                   gint length,
                                    packet_direction_t direction);
-static void set_aal_info(union wtap_pseudo_header *pseudo_header, gint length,
+static void set_aal_info(union wtap_pseudo_header *pseudo_header,
                          packet_direction_t direction);
 static void set_isdn_info(union wtap_pseudo_header *pseudo_header,
                           packet_direction_t direction);
 static void set_ppp_info(union wtap_pseudo_header *pseudo_header,
                          packet_direction_t direction);
 
+static gint wth_equal(gconstpointer v, gconstpointer v2);
+static guint wth_hash_func(gconstpointer v);
+static gint packet_offset_equal(gconstpointer v, gconstpointer v2);
+static guint packet_offset_hash_func(gconstpointer v);
 
-static gint prefix_equal(gconstpointer v, gconstpointer v2);
-static guint prefix_hash_func(gconstpointer v);
 static gboolean get_file_time_stamp(time_t *secs, guint32 *usecs);
 static gboolean free_line_prefix_info(gpointer key, gpointer value, gpointer user_data);
 
@@ -170,26 +168,16 @@ static gboolean free_line_prefix_info(gpointer key, gpointer value, gpointer use
 /********************************************/
 int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
 {
-    long    offset = 0;
+    gint64  offset = 0;
     time_t  timestamp;
     guint32 usecs;
-    gint firstline_length;
+    gint firstline_length = 0;
     dct2000_file_externals_t *file_externals;
 
     /* Clear errno before reading from the file */
     errno = 0;
 
 
-    /*********************************************************************/
-    /* Need entry in file_externals table                                */
-
-    /* Create file externals table if it doesn't yet exist */
-    if (file_externals_table == NULL)
-    {
-        file_externals_table = g_hash_table_new(prefix_hash_func, prefix_equal);
-    }
-
-
     /********************************************************************/
     /* First line needs to contain at least as many characters as magic */
 
@@ -207,6 +195,15 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
     }
 
 
+    /*********************************************************************/
+    /* Need entry in file_externals table                                */
+
+    /* Create file externals table if it doesn't yet exist */
+    if (file_externals_table == NULL)
+    {
+        file_externals_table = g_hash_table_new(wth_hash_func, wth_equal);
+    }
+
     /* Allocate a new file_externals structure */
     file_externals = g_malloc(sizeof(dct2000_file_externals_t));
     memset((void*)file_externals, '\0', sizeof(dct2000_file_externals_t));
@@ -255,10 +252,10 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
     wth->tsprecision = WTAP_FILE_TSPREC_USEC;
 
 
-    /**********************************************/
-    /* Initialise line_header_prefixes_table      */
-    file_externals->line_header_prefixes_table =
-        g_hash_table_new(prefix_hash_func, prefix_equal);
+    /***************************************************************/
+    /* Initialise packet_prefix_table (index is offset into file)  */
+    file_externals->packet_prefix_table =
+        g_hash_table_new(packet_offset_hash_func, packet_offset_equal);
 
     /* Add file_externals for this wtap into the global table */
     g_hash_table_insert(file_externals_table,
@@ -275,9 +272,9 @@ int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
 /* - return TRUE and details if found             */
 /**************************************************/
 gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
-                               long *data_offset)
+                               gint64 *data_offset)
 {
-    long offset = wth->data_offset;
+    gint64 offset = wth->data_offset;
     long dollar_offset, before_time_offset, after_time_offset;
     packet_direction_t direction;
     int encap;
@@ -296,7 +293,7 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
     while (1)
     {
         int line_length, seconds, useconds, data_chars;
-        long this_offset = offset;
+        gint64 this_offset = offset;
 
         /* Are looking for first packet after 2nd line */
         if (wth->data_offset == 0)
@@ -315,17 +312,19 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
             break;
         }
 
-        /* Try to parse the line as a message */
+        /* Try to parse the line as a frame record */
         if (parse_line(line_length, &seconds, &useconds,
                        &before_time_offset, &after_time_offset,
                        &dollar_offset,
-                       &data_chars, &direction, &encap, FALSE))
+                       &data_chars, &direction, &encap))
         {
             guchar *frame_buffer;
             int n;
             int stub_offset = 0;
             line_prefix_info_t *line_prefix_info;
             char timestamp_string[32];
+            gint64 *pkey = NULL;
+
             sprintf(timestamp_string, "%d.%04d", seconds, useconds/100);
 
             /* All packets go to Catapult DCT2000 stub dissector */
@@ -350,11 +349,14 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
 
             /* Get buffer pointer ready */
             buffer_assure_space(wth->frame_buffer,
-                                strlen(context_name)+1 +  /* Context name */
-                                1 +                       /* port */
-                                strlen(protocol_name)+1 + /* Protocol name */
-                                1 +                       /* direction */
-                                1 +                       /* encap */
+                                strlen(context_name)+1 +     /* Context name */
+                                1 +                          /* port */
+                                strlen(timestamp_string)+1 + /* timestamp */
+                                strlen(variant_name)+1 +     /* variant */
+                                strlen(outhdr_name)+1 +      /* outhdr */
+                                strlen(protocol_name)+1 +    /* Protocol name */
+                                1 +                          /* direction */
+                                1 +                          /* encap */
                                 (data_chars/2));
             frame_buffer = buffer_start_ptr(wth->frame_buffer);
 
@@ -381,23 +383,35 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
             /* Store the packet prefix in the hash table */
             line_prefix_info = g_malloc(sizeof(line_prefix_info_t));
 
+            /* Create and use buffer for contents before time */
             line_prefix_info->before_time = g_malloc(before_time_offset+1);
             strncpy(line_prefix_info->before_time, linebuff, before_time_offset);
             line_prefix_info->before_time[before_time_offset] = '\0';
 
-            line_prefix_info->after_time = g_malloc(dollar_offset - after_time_offset);
-            strncpy(line_prefix_info->after_time, linebuff+after_time_offset,
-                   dollar_offset - after_time_offset);
-            line_prefix_info->after_time[dollar_offset - after_time_offset-1] = '\0';
+            /* Create and use buffer for contents before time.
+               Do this only if it doesn't correspond to " l ", which is by far the most
+               common case. */
+            if (((size_t)(dollar_offset - after_time_offset -1) == strlen(" l ")) &&
+                (strncmp(linebuff+after_time_offset, " l ", strlen(" l ")) == 0))
+            {
+                line_prefix_info->after_time = NULL;
+            }
+            else
+            {
+                line_prefix_info->after_time = g_malloc(dollar_offset - after_time_offset);
+                strncpy(line_prefix_info->after_time, linebuff+after_time_offset,
+                        dollar_offset - after_time_offset);
+                line_prefix_info->after_time[dollar_offset - after_time_offset-1] = '\0';
+            }
 
             /* Add packet entry into table */
-            g_hash_table_insert(file_externals->line_header_prefixes_table,
-                                (void*)this_offset, line_prefix_info);
-
+            pkey = g_malloc(sizeof(pkey));
+            *pkey = this_offset;
+            g_hash_table_insert(file_externals->packet_prefix_table, pkey, line_prefix_info);
 
             /* Set pseudo-header if necessary */
             set_pseudo_header_info(wth, encap, this_offset, &wth->pseudo_header,
-                                   data_chars/2, direction);
+                                   direction);
 
             /* OK, we have packet details to return */
             *err = errno;
@@ -415,11 +429,11 @@ gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
 /* Read & seek function.                          */
 /**************************************************/
 static gboolean
-catapult_dct2000_seek_read(wtap *wth, long seek_off,
+catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
                            union wtap_pseudo_header *pseudo_header, guchar *pd,
                            int length, int *err, gchar **err_info)
 {
-    long offset = wth->data_offset;
+    gint64 offset = wth->data_offset;
     long dollar_offset, before_time_offset, after_time_offset;
     packet_direction_t direction;
     int encap;
@@ -444,7 +458,7 @@ catapult_dct2000_seek_read(wtap *wth, long seek_off,
     if (parse_line(length, &seconds, &useconds,
                    &before_time_offset, &after_time_offset,
                    &dollar_offset,
-                   &data_chars, &direction, &encap, TRUE))
+                   &data_chars, &direction, &encap))
     {
         int n;
         int stub_offset = 0;
@@ -457,7 +471,7 @@ catapult_dct2000_seek_read(wtap *wth, long seek_off,
 
         /*********************/
         /* Write stub header */
-        stub_offset = write_stub_header((char*)pd, timestamp_string,
+        stub_offset = write_stub_header((guchar*)pd, timestamp_string,
                                         direction, encap);
 
 
@@ -470,7 +484,7 @@ catapult_dct2000_seek_read(wtap *wth, long seek_off,
         }
 
         /* Set packet pseudo-header if necessary */
-        set_pseudo_header_info(wth, encap, seek_off, pseudo_header, data_chars/2, direction);
+        set_pseudo_header_info(wth, encap, seek_off, pseudo_header, direction);
 
         *err = errno = 0;
         return TRUE;
@@ -479,7 +493,8 @@ catapult_dct2000_seek_read(wtap *wth, long seek_off,
     /* If get here, must have failed */
     *err = errno;
     *err_info = g_strdup_printf("catapult dct2000: seek_read failed to read/parse "
-                                "line at position %ld", seek_off);
+                                "line at position %" G_GINT64_MODIFIER "d",
+                                seek_off);
     return FALSE;
 }
 
@@ -500,10 +515,10 @@ void catapult_dct2000_close(wtap *wth)
     }
 
     /* Free up its line prefix values */
-    g_hash_table_foreach_remove(file_externals->line_header_prefixes_table,
+    g_hash_table_foreach_remove(file_externals->packet_prefix_table,
                                 free_line_prefix_info, NULL);
     /* Free up its line prefix table */
-    g_hash_table_destroy(file_externals->line_header_prefixes_table);
+    g_hash_table_destroy(file_externals->packet_prefix_table);
 
     /* And remove the externals entry from the global table */
     g_hash_table_remove(file_externals_table, (void*)wth);
@@ -529,8 +544,8 @@ void catapult_dct2000_close(wtap *wth)
 gboolean catapult_dct2000_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err _U_)
 {
     /* Fill in other dump callbacks */
-       wdh->subtype_write = catapult_dct2000_dump;
-       wdh->subtype_close = catapult_dct2000_dump_close;
+    wdh->subtype_write = catapult_dct2000_dump;
+    wdh->subtype_close = catapult_dct2000_dump_close;
 
     return TRUE;
 }
@@ -603,8 +618,8 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
     /* Write out this packet's prefix, including calculated timestamp */
 
     /* Look up line data prefix using stored offset */
-    prefix = (line_prefix_info_t*)g_hash_table_lookup(file_externals->line_header_prefixes_table,
-                                                      (void*)pseudo_header->dct2000.seek_off);
+    prefix = (line_prefix_info_t*)g_hash_table_lookup(file_externals->packet_prefix_table,
+                                                      (const void*)&(pseudo_header->dct2000.seek_off));
 
     /* Write out text before timestamp */
     fwrite(prefix->before_time, 1, strlen(prefix->before_time), wdh->fh);
@@ -627,7 +642,14 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
     fwrite(time_string, 1, strlen(time_string), wdh->fh);
 
     /* Write out text between timestamp and start of hex data */
-    fwrite(prefix->after_time, 1, strlen(prefix->after_time), wdh->fh);
+    if (prefix->after_time == NULL)
+    {
+        fwrite(" l ", 1, strlen(" l "), wdh->fh);
+    }
+    else
+    {
+        fwrite(prefix->after_time, 1, strlen(prefix->after_time), wdh->fh);
+    }
 
 
     /****************************************************************/
@@ -648,6 +670,14 @@ gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
     for (; pd[n] != '\0'; n++);
     n++;
 
+    /* Variant number (as string) */
+    for (; pd[n] != '\0'; n++);
+    n++;
+
+    /* Outhdr (as string) */
+    for (; pd[n] != '\0'; n++);
+    n++;
+
     /* Direction & encap */
     n += 2;
 
@@ -695,7 +725,7 @@ static gboolean catapult_dct2000_dump_close(wtap_dumper *wdh _U_, int *err _U_)
 /* - on return 'offset' will point to the next position to read from  */
 /* - return TRUE if this read is successful                           */
 /**********************************************************************/
-gboolean read_new_line(FILE_T fh, long *offset, gint *length)
+gboolean read_new_line(FILE_T fh, gint64 *offset, gint *length)
 {
     char *result;
 
@@ -733,26 +763,28 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
                     long *before_time_offset, long *after_time_offset,
                     long *data_offset, gint *data_chars,
                     packet_direction_t *direction,
-                    int *encap,
-                    gboolean seek_read)
+                    int *encap)
 {
     int  n = 0;
     int  port_digits = 0;
     char port_number_string[MAX_PORT_DIGITS+1];
     int  variant_digits = 0;
+    int  variant = 1;
     int  protocol_chars = 0;
+    int  outhdr_chars = 0;
 
     char seconds_buff[MAX_SECONDS_CHARS+1];
     int  seconds_chars;
     char subsecond_decimals_buff[MAX_SUBSECOND_DECIMALS+1];
     int  subsecond_decimals_chars;
+    int  skip_first_byte = FALSE;
 
     gboolean atm_header_present = FALSE;
 
     /* Read context name until find '.' */
     for (n=0; linebuff[n] != '.' && (n < MAX_CONTEXT_NAME) && (n+1 < line_length); n++)
     {
-        if (!isalnum(linebuff[n]) && (linebuff[n] != '_'))
+        if (!isalnum((int)linebuff[n]) && (linebuff[n] != '_'))
         {
             return FALSE;
         }
@@ -778,7 +810,7 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
          (linebuff[n] != '/') && (port_digits <= MAX_PORT_DIGITS) && (n+1 < line_length);
          n++, port_digits++)
     {
-        if (!isdigit(linebuff[n]))
+        if (!isdigit((int)linebuff[n]))
         {
             return FALSE;
         }
@@ -805,7 +837,7 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
          (linebuff[n] != '/') && (protocol_chars < MAX_PROTOCOL_NAME) && (n < line_length);
          n++, protocol_chars++)
     {
-        if (!isalnum(linebuff[n]) && linebuff[n] != '_')
+        if (!isalnum((int)linebuff[n]) && linebuff[n] != '_')
         {
             return FALSE;
         }
@@ -827,25 +859,99 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     n++;
 
 
+    /* Following the / is the variant number.  No digits indicate 1 */
+    for (variant_digits = 0;
+         (isdigit((int)linebuff[n])) && (variant_digits <= MAX_VARIANT_DIGITS) && (n+1 < line_length);
+         n++, variant_digits++)
+    {
+        if (!isdigit((int)linebuff[n]))
+        {
+            return FALSE;
+        }
+        variant_name[variant_digits] = linebuff[n];
+    }
+    if (variant_digits > MAX_VARIANT_DIGITS || (n+1 >= line_length))
+    {
+        return FALSE;
+    }
+    if (variant_digits > 0)
+    {
+        variant_name[variant_digits] = '\0';
+        variant = atoi(variant_name);
+    }
+    else
+    {
+        strcpy(variant_name, "1");
+    }
+
+
+    /* Outheader values may follow */
+    outhdr_name[0] = '\0';
+    if (linebuff[n] == ',')
+    {
+        /* Skip , */
+        n++;
+
+        for (outhdr_chars = 0;
+             (isdigit((int)linebuff[n]) || linebuff[n] == ',') &&
+             (outhdr_chars <= MAX_OUTHDR_NAME) && (n+1 < line_length);
+             n++, outhdr_chars++)
+        {
+            if (!isdigit((int)linebuff[n]) && (linebuff[n] != ','))
+            {
+                return FALSE;
+            }
+            outhdr_name[outhdr_chars] = linebuff[n];
+        }
+        if (outhdr_chars > MAX_OUTHDR_NAME || (n+1 >= line_length))
+        {
+            return FALSE;
+        }
+        /* Terminate (possibly empty) string */
+        outhdr_name[outhdr_chars] = '\0';
+    }
+
+
+
+
     /******************************************************************/
     /* Now check whether we know how to use a packet of this protocol */
 
-    if ((strcmp(protocol_name, "ip") == 0)  || (strcmp(protocol_name, "sctp") == 0))
+    if ((strcmp(protocol_name, "ip") == 0) ||
+        (strcmp(protocol_name, "sctp") == 0) ||
+        (strcmp(protocol_name, "gre") == 0) ||
+        (strcmp(protocol_name, "mipv6") == 0))
     {
         *encap = WTAP_ENCAP_RAW_IP;
     }
     else
 
-    /* For ATM protocols, we need to read the separate atm headerparse */
+    /* FP may be carried over ATM, which has separate atm header to parse */
     if ((strcmp(protocol_name, "fp") == 0) ||
         (strcmp(protocol_name, "fp_r4") == 0) ||
         (strcmp(protocol_name, "fp_r5") == 0) ||
         (strcmp(protocol_name, "fp_r6") == 0))
     {
+        if ((variant > 256) && (variant % 256 == 3))
+        {
+            /* FP over udp is contained in IPPrim... */
+            *encap = 0;
+        }
+        else
+        {
+            /* FP over AAL0 or AAL2 */
+            *encap = WTAP_ENCAP_ATM_PDUS_UNTRUNCATED;
+            atm_header_present = TRUE;
+        }
+    }
+    else if (strcmp(protocol_name, "fpiur_r5") == 0)
+    {
+        /* FP (IuR) over AAL2 */
         *encap = WTAP_ENCAP_ATM_PDUS_UNTRUNCATED;
         atm_header_present = TRUE;
     }
 
+
     else
     if (strcmp(protocol_name, "ppp") == 0)
     {
@@ -854,7 +960,13 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     else
     if (strcmp(protocol_name, "isdn_l3") == 0)
     {
-        /* Despite the name, this does seem to correspond to L2... */
+       /* TODO: find out what this byte means... */
+        skip_first_byte = TRUE;
+        *encap = WTAP_ENCAP_ISDN;
+    }
+    else
+    if (strcmp(protocol_name, "isdn_l2") == 0)
+    {
         *encap = WTAP_ENCAP_ISDN;
     }
     else
@@ -879,46 +991,18 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
         *encap = DCT2000_ENCAP_MTP2;
     }
     else
+    if ((strcmp(protocol_name, "nbap") == 0) ||
+        (strcmp(protocol_name, "nbap_r4") == 0) ||
+        (strncmp(protocol_name, "nbap_sscfuni", strlen("nbap_sscfuni")) == 0))
     {
-        /* Only reject protocol if reading for the first time and preference
-           setting says board ports only.  This should not fail to read a
-           non board-port protocol on re-reading because the preference setting
-           has since changed...
-        */
-        if (catapult_dct2000_board_ports_only && !seek_read)
-        {
-            return FALSE;
-        }
-        else
-        {
-            /* Not a supported protocol/encap, but should show as raw data anyway */
-            *encap = DCT2000_ENCAP_UNHANDLED;
-        }
-    }
-
-
-    /* Following the / is the variant number.  No digits indicate 1 */
-    for (variant_digits = 0;
-         (isdigit(linebuff[n])) && (variant_digits <= MAX_VARIANT_DIGITS) && (n+1 < line_length);
-         n++, variant_digits++)
-    {
-        if (!isdigit(linebuff[n]))
-        {
-            return FALSE;
-        }
-        variant_name[variant_digits] = linebuff[n];
-    }
-    if (variant_digits > MAX_VARIANT_DIGITS || (n+1 >= line_length))
-    {
-        return FALSE;
-    }
-    if (variant_digits > 0)
-    {
-        variant_name[variant_digits] = '\0';
+        /* The entire message in these cases is nbap, so use an encap value. */
+        *encap = DCT2000_ENCAP_NBAP;
     }
     else
     {
-        strcpy(variant_name, "1");
+        /* Not a supported board port protocol/encap, but can show as raw data or
+           in some cases find protocol embedded inside primitive */
+        *encap = DCT2000_ENCAP_UNHANDLED;
     }
 
 
@@ -938,7 +1022,7 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
 
         /* Read consecutive hex chars into atm header buffer */
         for (;
-             (isalnum(linebuff[n]) &&
+             (isalnum((int)linebuff[n]) &&
               (n < line_length) &&
               (header_chars_seen < AAL_HEADER_CHARS));
              n++, header_chars_seen++)
@@ -946,6 +1030,13 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
             aal_header_chars[header_chars_seen] = linebuff[n];
         }
 
+        /* Sometimes see strange encoding of cid in last (non-digit) character */
+        if (header_chars_seen == (AAL_HEADER_CHARS-1))
+        {
+            aal_header_chars[AAL_HEADER_CHARS-1] = linebuff[n];
+            header_chars_seen++;
+        }
+
         if (header_chars_seen != AAL_HEADER_CHARS || n >= line_length)
         {
             return FALSE;
@@ -982,7 +1073,7 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     /* Find and read the timestamp                                       */
 
     /* Now scan to the next digit, which should be the start of the timestamp */
-    for (; !isdigit(linebuff[n]) && (n < line_length); n++);
+    for (; !isdigit((int)linebuff[n]) && (n < line_length); n++);
     if (n >= line_length)
     {
         return FALSE;
@@ -997,7 +1088,7 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
          (n < line_length);
          n++, seconds_chars++)
     {
-        if (!isdigit(linebuff[n]))
+        if (!isdigit((int)linebuff[n]))
         {
             /* Found a non-digit before decimal point. Fail */
             return FALSE;
@@ -1009,7 +1100,7 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
         /* Didn't fit in buffer.  Fail rather than use truncated */
         return FALSE;
     }
-    
+
     /* Convert found value into number */
     seconds_buff[seconds_chars] = '\0';
     *seconds = atoi(seconds_buff);
@@ -1029,7 +1120,7 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
          (n < line_length);
          n++, subsecond_decimals_chars++)
     {
-        if (!isdigit(linebuff[n]))
+        if (!isdigit((int)linebuff[n]))
         {
             return FALSE;
         }
@@ -1067,15 +1158,14 @@ gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
     /* Set number of chars that comprise the hex string protocol data */
     *data_chars = line_length - n;
 
-    /* Need to skip first byte (2 hex string chars) from ISDN messages.
-       TODO: find out what this byte means...
-    */
-    if (*encap == WTAP_ENCAP_ISDN)
+    /* May need to skip first byte (2 hex string chars) */
+    if (skip_first_byte)
     {
         *data_offset += 2;
         *data_chars -= 2;
     }
 
+
     return TRUE;
 }
 
@@ -1102,10 +1192,14 @@ int write_stub_header(guchar *frame_buffer, char *timestamp_string,
     strcpy((char*)&frame_buffer[stub_offset], protocol_name);
     stub_offset += (strlen(protocol_name) + 1);
 
-    /* Protocol variant number */
+    /* Protocol variant number (as string) */
     strcpy((void*)&frame_buffer[stub_offset], variant_name);
     stub_offset += (strlen(variant_name) + 1);
 
+    /* Outhdr */
+    strcpy((char*)&frame_buffer[stub_offset], outhdr_name);
+    stub_offset += (strlen(outhdr_name) + 1);
+
     /* Direction */
     frame_buffer[stub_offset] = direction;
     stub_offset++;
@@ -1113,7 +1207,7 @@ int write_stub_header(guchar *frame_buffer, char *timestamp_string,
     /* Encap */
     frame_buffer[stub_offset] = (guint8)encap;
     stub_offset++;
-    
+
     return stub_offset;
 }
 
@@ -1123,9 +1217,8 @@ int write_stub_header(guchar *frame_buffer, char *timestamp_string,
 /**************************************************************/
 void set_pseudo_header_info(wtap *wth,
                             int pkt_encap,
-                            long file_offset,
+                            gint64 file_offset,
                             union wtap_pseudo_header *pseudo_header,
-                            gint length,
                             packet_direction_t direction)
 {
     pseudo_header->dct2000.seek_off = file_offset;
@@ -1134,7 +1227,7 @@ void set_pseudo_header_info(wtap *wth,
     switch (pkt_encap)
     {
         case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
-            set_aal_info(pseudo_header, length, direction);
+            set_aal_info(pseudo_header, direction);
             break;
         case WTAP_ENCAP_ISDN:
             set_isdn_info(pseudo_header, direction);
@@ -1153,8 +1246,7 @@ void set_pseudo_header_info(wtap *wth,
 /*********************************************/
 /* Fill in atm pseudo-header with known info */
 /*********************************************/
-void set_aal_info(union wtap_pseudo_header *pseudo_header, gint length,
-                  packet_direction_t direction)
+void set_aal_info(union wtap_pseudo_header *pseudo_header, packet_direction_t direction)
 {
     /* 'aal_head_chars' has this format (for AAL2 at least):
        Global Flow Control (4 bits) | VPI (8 bits) | VCI (16 bits) |
@@ -1174,7 +1266,7 @@ void set_aal_info(union wtap_pseudo_header *pseudo_header, gint length,
     /* Assume always AAL2 for FP */
     pseudo_header->dct2000.inner_pseudo_header.atm.aal = AAL_2;
 
-    pseudo_header->dct2000.inner_pseudo_header.atm.type = TRAF_UNKNOWN;
+    pseudo_header->dct2000.inner_pseudo_header.atm.type = TRAF_UMTS_FP;
     pseudo_header->dct2000.inner_pseudo_header.atm.subtype = TRAF_ST_UNKNOWN;
 
     /* vpi is 8 bits (2nd & 3rd nibble) */
@@ -1192,9 +1284,20 @@ void set_aal_info(union wtap_pseudo_header *pseudo_header, gint length,
     /* 0 means we don't know how many cells the frame comprises. */
     pseudo_header->dct2000.inner_pseudo_header.atm.cells = 0;
 
-    pseudo_header->dct2000.inner_pseudo_header.atm.aal5t_u2u = 0;
-    pseudo_header->dct2000.inner_pseudo_header.atm.aal5t_len = length;
-    pseudo_header->dct2000.inner_pseudo_header.atm.aal5t_chksum = 0;
+    /* cid is usually last byte.  Unless last char is not hex digit, in which
+       case cid is derived from last char in ascii */
+    if (isalnum((int)aal_header_chars[11]))
+    {
+        pseudo_header->dct2000.inner_pseudo_header.atm.aal2_cid =
+            ((hex_from_char(aal_header_chars[10]) << 4) |
+              hex_from_char(aal_header_chars[11]));
+    }
+    else
+    {
+        pseudo_header->dct2000.inner_pseudo_header.atm.aal2_cid =
+            (int)aal_header_chars[11] - 48;
+    }
+
 }
 
 
@@ -1264,23 +1367,40 @@ gchar char_from_hex(guchar hex)
     return hex_lookup[hex];
 }
 
-
-/********************************************/
-/* Equality test for line-prefix hash table */
-/********************************************/
-gint prefix_equal(gconstpointer v, gconstpointer v2)
+/***************************************************/
+/* Equality function for file_externals hash table */
+/***************************************************/
+gint wth_equal(gconstpointer v, gconstpointer v2)
 {
     return (v == v2);
 }
 
+/***********************************************/
+/* Hash function for file_externals hash table */
+/***********************************************/
+guint wth_hash_func(gconstpointer v)
+{
+    return (guint)(unsigned long)v;
+}
+
+
+/***********************************************/
+/* Equality test for packet prefix hash tables */
+/***********************************************/
+gint packet_offset_equal(gconstpointer v, gconstpointer v2)
+{
+    /* Dereferenced pointers must have same gint64 offset value */
+    return (*(const gint64*)v == *(const gint64*)v2);
+}
+
 
 /********************************************/
-/* Hash function for line-prefix hash table */
+/* Hash function for packet-prefix hash table */
 /********************************************/
-guint prefix_hash_func(gconstpointer v)
+guint packet_offset_hash_func(gconstpointer v)
 {
-    /* Just use pointer itself (is actually byte offset of line in file) */ 
-    return (guint)v;
+    /* Use low-order bits of git64 offset value */
+    return (guint)(*(const gint64*)v);
 }
 
 
@@ -1362,14 +1482,20 @@ gboolean get_file_time_stamp(time_t *secs, guint32 *usecs)
 }
 
 /* Free the data allocated inside a line_prefix_info_t */
-gboolean free_line_prefix_info(gpointer key _U_, gpointer value,
+gboolean free_line_prefix_info(gpointer key, gpointer value,
                                gpointer user_data _U_)
 {
     line_prefix_info_t *info = (line_prefix_info_t*)value;
 
+    /* Free the 64-bit key value */
+    g_free(key);
+
     /* Free the strings inside */
     g_free(info->before_time);
-    g_free(info->after_time);
+    if (info->after_time)
+    {
+        g_free(info->after_time);
+    }
 
     /* And the structure itself */
     g_free(info);