#define MAX_FIRST_LINE_LENGTH 200
#define MAX_TIMESTAMP_LINE_LENGTH 100
-#define MAX_LINE_LENGTH 32000
+#define MAX_LINE_LENGTH 65536
+#define MAX_TIMESTAMP_LEN 32
#define MAX_SECONDS_CHARS 16
#define MAX_SUBSECOND_DECIMALS 4
#define MAX_CONTEXT_NAME 64
#define MAX_PROTOCOL_NAME 64
#define MAX_PORT_DIGITS 2
#define MAX_VARIANT_DIGITS 32
+#define MAX_OUTHDR_NAME 256
#define AAL_HEADER_CHARS 12
/* TODO:
+ - support for FP over AAL0
+ - support for IuR interface FP
- support for x.25?
*/
} packet_direction_t;
+/***********************************************************************/
+/* For each line, store (in case we need to dump): */
+/* - String before time field */
+/* - String beween time field and data (if NULL assume " l ") */
typedef struct
{
gchar *before_time;
gchar *after_time;
} line_prefix_info_t;
+
/*******************************************************************/
-/* Information stored external to a file (wtap) needed for dumping */
+/* Information stored external to a file (wtap) needed for reading and dumping */
typedef struct dct2000_file_externals
{
+ /* Remember the time at the start of capture */
+ time_t start_secs;
+ guint32 start_usecs;
+
+ /*
+ * The following information is needed only for dumping.
+ *
+ * XXX - Wiretap is not *supposed* to require that a packet being
+ * dumped come from a file of the same type that you currently have
+ * open; this should be fixed.
+ */
+
/* Buffer to hold first line, including magic and format number */
gchar firstline[MAX_FIRST_LINE_LENGTH];
gint firstline_length;
gint secondline_length;
/* Hash table to store text prefix data part of displayed packets.
- Records (file offset -> pre-data-prefix-string)
- N.B. This is only needed for dumping
+ Records (file offset -> line_prefix_info_t)
*/
- GHashTable *line_header_prefixes_table;
+ GHashTable *packet_prefix_table;
} dct2000_file_externals_t;
-/* This global table maps wtap -> file_external structs */
-static GHashTable *file_externals_table = NULL;
-
-
-/***********************************************************/
-/* Transient data used for parsing */
-
-/* Buffer to hold a single text line read from the file */
-static gchar linebuff[MAX_LINE_LENGTH];
-
-/* Buffer for separate AAL header */
-static gchar aal_header_chars[AAL_HEADER_CHARS];
-
/* 'Magic number' at start of Catapult DCT2000 .out files. */
static const gchar catapult_dct2000_magic[] = "Session Transcript";
-/* Context name + port that the packet was captured at */
-static gchar context_name[MAX_CONTEXT_NAME];
-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];
-
-
-/*************************************************/
-/* 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 */
+/* Functions called from wiretap core */
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,
+ guint8 *pd, int length,
int *err, gchar **err_info);
static void catapult_dct2000_close(wtap *wth);
static gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
const union wtap_pseudo_header *pseudo_header,
- const guchar *pd, int *err);
-static gboolean catapult_dct2000_dump_close(wtap_dumper *wdh, int *err);
+ const guint8 *pd, int *err);
/************************************************************/
/* Private helper functions */
-static gboolean read_new_line(FILE_T fh, long *offset, gint *length);
-static gboolean parse_line(gint line_length, gint *seconds, gint *useconds,
+static gboolean read_new_line(FILE_T fh, gint64 *offset, gint *length,
+ gchar *buf, size_t bufsize);
+static gboolean parse_line(char *linebuff, 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);
-static int write_stub_header(guchar *frame_buffer, char *timestamp_string,
- packet_direction_t direction, int encap);
-static guchar hex_from_char(gchar c);
-static gchar char_from_hex(guchar hex);
+ int *encap, int *is_comment,
+ gchar *aal_header_chars,
+ gchar *context_name, guint8 *context_portp,
+ gchar *protocol_name, gchar *variant_name,
+ gchar *outhdr_name);
+static int write_stub_header(guint8 *frame_buffer, char *timestamp_string,
+ packet_direction_t direction, int encap,
+ gchar *context_name, guint8 context_port,
+ gchar *protocol_name, gchar *variant_name,
+ gchar *outhdr_name);
+static guint8 hex_from_char(gchar c);
+static guint8 hex_byte_from_chars(gchar *c);
+static gchar char_from_hex(guint8 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,
- packet_direction_t direction);
+ packet_direction_t direction,
+ gchar *aal_header_chars);
+static void set_aal_info(union wtap_pseudo_header *pseudo_header,
+ packet_direction_t direction,
+ gchar *aal_header_chars);
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 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 get_file_time_stamp(gchar *linebuff, time_t *secs, guint32 *usecs);
static gboolean free_line_prefix_info(gpointer key, gpointer value, gpointer user_data);
/********************************************/
-/* Open file */
+/* Open file (for reading) */
/********************************************/
-int catapult_dct2000_open(wtap *wth, int *err, gchar **err_info _U_)
+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;
+ static gchar linebuff[MAX_LINE_LENGTH];
/* 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 */
- read_new_line(wth->fh, &offset, &firstline_length);
+ read_new_line(wth->fh, &offset, &firstline_length, linebuff,
+ sizeof linebuff);
if (((size_t)firstline_length < strlen(catapult_dct2000_magic)) ||
- firstline_length >= MAX_FIRST_LINE_LENGTH)
- {
+ firstline_length >= MAX_FIRST_LINE_LENGTH) {
+
return 0;
}
/* This file is not for us if it doesn't match our signature */
- if (memcmp(catapult_dct2000_magic, linebuff, strlen(catapult_dct2000_magic)) != 0)
- {
+ if (memcmp(catapult_dct2000_magic, linebuff, strlen(catapult_dct2000_magic)) != 0) {
return 0;
}
- /* Allocate a new file_externals structure */
+ /*********************************************************************/
+ /* Need entry in file_externals table */
+
+ /* Allocate a new file_externals structure for this file */
file_externals = g_malloc(sizeof(dct2000_file_externals_t));
memset((void*)file_externals, '\0', sizeof(dct2000_file_externals_t));
/* Copy this first line into buffer so could write out later */
- strncpy(file_externals->firstline, linebuff, firstline_length);
+ g_strlcpy(file_externals->firstline, linebuff, firstline_length+1);
file_externals->firstline_length = firstline_length;
/***********************************************************/
/* Second line contains file timestamp */
- /* Store this offset in in wth->capture->catapult_dct2000 */
+ /* Store this offset in in file_externals */
- read_new_line(wth->fh, &offset, &(file_externals->secondline_length));
+ read_new_line(wth->fh, &offset, &(file_externals->secondline_length),
+ linebuff, sizeof linebuff);
if ((file_externals->secondline_length >= MAX_TIMESTAMP_LINE_LENGTH) ||
- (!get_file_time_stamp(×tamp, &usecs)))
- {
+ (!get_file_time_stamp(linebuff, ×tamp, &usecs))) {
+
/* Give up if file time line wasn't valid */
g_free(file_externals);
return 0;
}
- wth->capture.catapult_dct2000 = g_malloc(sizeof(catapult_dct2000_t));
- wth->capture.catapult_dct2000->start_secs = timestamp;
- wth->capture.catapult_dct2000->start_usecs = usecs;
+ /* Fill in timestamp */
+ file_externals->start_secs = timestamp;
+ file_externals->start_usecs = usecs;
/* Copy this second line into buffer so could write out later */
- strncpy(file_externals->secondline, linebuff, file_externals->secondline_length);
+ g_strlcpy(file_externals->secondline, linebuff, file_externals->secondline_length+1);
/************************************************************/
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,
- (void*)wth, (void*)file_externals);
+ /* Set this wtap to point to the file_externals */
+ wth->priv = (void*)file_externals;
*err = errno;
return 1;
/**************************************************/
-/* Read function. */
+/* Read packet function. */
/* Look for and read the next usable packet */
/* - return TRUE and details if found */
/**************************************************/
-gboolean catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
- long *data_offset)
+static gboolean
+catapult_dct2000_read(wtap *wth, int *err, gchar **err_info _U_,
+ 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;
- /* Find wtap external structure for this wtap */
+ /* Get wtap external structure for this wtap */
dct2000_file_externals_t *file_externals =
- (dct2000_file_externals_t*)g_hash_table_lookup(file_externals_table, wth);
+ (dct2000_file_externals_t*)wth->priv;
/* There *has* to be an entry for this wth */
- if (!file_externals)
- {
+ if (!file_externals) {
return FALSE;
}
- /* Search for a line containing a usable message */
- while (1)
- {
+ /* Search for a line containing a usable packet */
+ while (1) {
int line_length, seconds, useconds, data_chars;
- long this_offset = offset;
+ int is_comment = FALSE;
+ gint64 this_offset = offset;
+ static gchar linebuff[MAX_LINE_LENGTH+1];
+ gchar aal_header_chars[AAL_HEADER_CHARS];
+ gchar context_name[MAX_CONTEXT_NAME];
+ guint8 context_port;
+ gchar protocol_name[MAX_PROTOCOL_NAME+1];
+ gchar variant_name[MAX_VARIANT_DIGITS+1];
+ gchar outhdr_name[MAX_OUTHDR_NAME+1];
/* Are looking for first packet after 2nd line */
- if (wth->data_offset == 0)
- {
+ if (wth->data_offset == 0) {
this_offset += (file_externals->firstline_length+1+
file_externals->secondline_length+1);
}
errno = 0;
/* Read a new line from file into linebuff */
- if (read_new_line(wth->fh, &offset, &line_length) == FALSE)
- {
- /* Get out when no more lines to be read */
+ if (read_new_line(wth->fh, &offset, &line_length, linebuff,
+ sizeof linebuff) == FALSE) {
+ /* Get out if no more lines can be read */
break;
}
- /* Try to parse the line as a message */
- if (parse_line(line_length, &seconds, &useconds,
+ /* Try to parse the line as a frame record */
+ if (parse_line(linebuff, line_length, &seconds, &useconds,
&before_time_offset, &after_time_offset,
&dollar_offset,
- &data_chars, &direction, &encap, FALSE))
- {
- guchar *frame_buffer;
+ &data_chars, &direction, &encap, &is_comment,
+ aal_header_chars,
+ context_name, &context_port,
+ protocol_name, variant_name, outhdr_name)) {
+ guint8 *frame_buffer;
int n;
int stub_offset = 0;
line_prefix_info_t *line_prefix_info;
- char timestamp_string[32];
- sprintf(timestamp_string, "%d.%04d", seconds, useconds/100);
+ char timestamp_string[MAX_TIMESTAMP_LEN+1];
+ gint64 *pkey = NULL;
+
+ g_snprintf(timestamp_string, MAX_TIMESTAMP_LEN, "%d.%04d", seconds, useconds/100);
+
+ wth->phdr.presence_flags = WTAP_HAS_TS;
/* All packets go to Catapult DCT2000 stub dissector */
wth->phdr.pkt_encap = WTAP_ENCAP_CATAPULT_DCT2000;
wth->data_offset = this_offset + line_length + 1;
/* Fill in timestamp (capture base + packet offset) */
- wth->phdr.ts.secs = wth->capture.catapult_dct2000->start_secs + seconds;
- if ((wth->capture.catapult_dct2000->start_usecs + useconds) >= 1000000)
- {
+ wth->phdr.ts.secs = file_externals->start_secs + seconds;
+ if ((file_externals->start_usecs + useconds) >= 1000000) {
wth->phdr.ts.secs++;
}
wth->phdr.ts.nsecs =
- ((wth->capture.catapult_dct2000->start_usecs + useconds) % 1000000) *1000;
+ ((file_externals->start_usecs + useconds) % 1000000) *1000;
/* 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 */
- (data_chars/2));
+ 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 */
+ (is_comment ? data_chars : (data_chars/2)));
frame_buffer = buffer_start_ptr(wth->frame_buffer);
/*********************/
/* Write stub header */
stub_offset = write_stub_header(frame_buffer, timestamp_string,
- direction, encap);
+ direction, encap, context_name,
+ context_port,
+ protocol_name, variant_name,
+ outhdr_name);
/* Binary data length is half bytestring length + stub header */
- wth->phdr.len = data_chars/2 + stub_offset;
- wth->phdr.caplen = data_chars/2 + stub_offset;
+ wth->phdr.len = stub_offset + (is_comment ? data_chars : (data_chars/2));
+ wth->phdr.caplen = stub_offset + (is_comment ? data_chars : (data_chars/2));
- /*************************/
- /* Copy data into buffer */
- for (n=0; n <= data_chars; n+=2)
- {
- frame_buffer[stub_offset + n/2] =
- (hex_from_char(linebuff[dollar_offset+n]) << 4) |
- hex_from_char(linebuff[dollar_offset+n+1]);
+ if (!is_comment) {
+ /****************************************************/
+ /* Copy data into buffer, converting from ascii hex */
+ for (n=0; n <= data_chars; n+=2) {
+ frame_buffer[stub_offset + n/2] =
+ hex_byte_from_chars(linebuff+dollar_offset+n);
+ }
+ }
+ else {
+ /***********************************************************/
+ /* Copy packet data into buffer, just copying ascii chars */
+ for (n=0; n <= data_chars; n++) {
+ frame_buffer[stub_offset + n] = linebuff[dollar_offset+n];
+ }
}
/* Store the packet prefix in the hash table */
line_prefix_info = g_malloc(sizeof(line_prefix_info_t));
- 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';
+ /* Create and use buffer for contents before time */
+ line_prefix_info->before_time = g_malloc(before_time_offset+2);
+ g_strlcpy(line_prefix_info->before_time, linebuff, before_time_offset+1);
+ line_prefix_info->before_time[before_time_offset+1] = '\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)) {
- /* Add packet entry into table */
- g_hash_table_insert(file_externals->line_header_prefixes_table,
- (void*)this_offset, line_prefix_info);
+ line_prefix_info->after_time = NULL;
+ }
+ else {
+ /* Allocate & write buffer for line between timestamp and data */
+ line_prefix_info->after_time = g_malloc(dollar_offset - after_time_offset);
+ g_strlcpy(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 */
+ 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, aal_header_chars);
/* OK, we have packet details to return */
*err = errno;
/* Read & seek function. */
/**************************************************/
static gboolean
-catapult_dct2000_seek_read(wtap *wth, long seek_off,
- union wtap_pseudo_header *pseudo_header, guchar *pd,
+catapult_dct2000_seek_read(wtap *wth, gint64 seek_off,
+ union wtap_pseudo_header *pseudo_header, guint8 *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;
+ static gchar linebuff[MAX_LINE_LENGTH+1];
+ gchar aal_header_chars[AAL_HEADER_CHARS];
+ gchar context_name[MAX_CONTEXT_NAME];
+ guint8 context_port;
+ gchar protocol_name[MAX_PROTOCOL_NAME+1];
+ gchar variant_name[MAX_VARIANT_DIGITS+1];
+ gchar outhdr_name[MAX_OUTHDR_NAME+1];
+ int is_comment = FALSE;
packet_direction_t direction;
int encap;
int seconds, useconds, data_chars;
*err = errno = 0;
/* Seek to beginning of packet */
- if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
- {
+ if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
return FALSE;
}
- /* Re-read whole line (this should succeed) */
- if (read_new_line(wth->random_fh, &offset, &length) == FALSE)
- {
+ /* Re-read whole line (this really should succeed) */
+ if (read_new_line(wth->random_fh, &offset, &length, linebuff,
+ sizeof linebuff) == FALSE) {
return FALSE;
}
/* Try to parse this line again (should succeed as re-reading...) */
- if (parse_line(length, &seconds, &useconds,
+ if (parse_line(linebuff, length, &seconds, &useconds,
&before_time_offset, &after_time_offset,
&dollar_offset,
- &data_chars, &direction, &encap, TRUE))
- {
+ &data_chars, &direction, &encap, &is_comment,
+ aal_header_chars,
+ context_name, &context_port,
+ protocol_name, variant_name, outhdr_name)) {
int n;
int stub_offset = 0;
- char timestamp_string[32];
- sprintf(timestamp_string, "%d.%04d", seconds, useconds/100);
+ char timestamp_string[MAX_TIMESTAMP_LEN+1];
+ g_snprintf(timestamp_string, MAX_TIMESTAMP_LEN, "%d.%04d", seconds, useconds/100);
/* Make sure all packets go to catapult dct2000 dissector */
wth->phdr.pkt_encap = WTAP_ENCAP_CATAPULT_DCT2000;
/*********************/
/* Write stub header */
- stub_offset = write_stub_header((char*)pd, timestamp_string,
- direction, encap);
-
-
- /********************************/
- /* Copy packet data into buffer */
- for (n=0; n <= data_chars; n+=2)
- {
- pd[stub_offset + n/2] = (hex_from_char(linebuff[dollar_offset+n]) << 4) |
- hex_from_char(linebuff[dollar_offset+n+1]);
+ stub_offset = write_stub_header(pd, timestamp_string,
+ direction, encap, context_name,
+ context_port,
+ protocol_name, variant_name,
+ outhdr_name);
+
+
+ if (!is_comment) {
+ /***********************************************************/
+ /* Copy packet data into buffer, converting from ascii hex */
+ for (n=0; n <= data_chars; n+=2) {
+ pd[stub_offset + n/2] = hex_byte_from_chars(linebuff+dollar_offset+n);
+ }
+ }
+ else {
+ /***********************************************************/
+ /* Copy packet data into buffer, just copying ascii chars */
+ for (n=0; n <= data_chars; n++) {
+ pd[stub_offset+n] = linebuff[dollar_offset+n];
+ }
}
/* 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,
+ aal_header_chars);
*err = errno = 0;
return TRUE;
/* 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;
}
-/******************************************/
-/* Free dct2000-specific capture info */
-/******************************************/
-void catapult_dct2000_close(wtap *wth)
+/***************************************************************************/
+/* Free dct2000-specific capture info from file that was open for reading */
+/***************************************************************************/
+static void
+catapult_dct2000_close(wtap *wth)
{
- /* Look up externals for this file */
+ /* Get externals for this file */
dct2000_file_externals_t *file_externals =
- (dct2000_file_externals_t*)g_hash_table_lookup(file_externals_table, wth);
+ (dct2000_file_externals_t*)wth->priv;
/* The entry *has* to be found */
- if (!file_externals)
- {
+ if (!file_externals) {
return;
}
/* 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);
-
- /* And remove the externals entry from the global table */
- g_hash_table_remove(file_externals_table, (void*)wth);
-
- /* And free up file_externals itself */
- g_free(file_externals);
-
- /* Also free this capture info */
- g_free(wth->capture.catapult_dct2000);
+ g_hash_table_destroy(file_externals->packet_prefix_table);
}
/* Dump functions */
/***************************/
+typedef struct {
+ gboolean first_packet_written;
+ struct wtap_nstime start_time;
+} dct2000_dump_t;
+
/*****************************************************/
/* The file that we are writing to has been opened. */
/* Set other dump callbacks. */
/*****************************************************/
-gboolean catapult_dct2000_dump_open(wtap_dumper *wdh, gboolean cant_seek _U_, int *err _U_)
+gboolean
+catapult_dct2000_dump_open(wtap_dumper *wdh, 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;
return TRUE;
}
/* Respond to queries about which encap types we support */
/* writing to. */
/*********************************************************/
-int catapult_dct2000_dump_can_write_encap(int encap)
+int
+catapult_dct2000_dump_can_write_encap(int encap)
{
- switch (encap)
- {
+ switch (encap) {
case WTAP_ENCAP_CATAPULT_DCT2000:
/* We support this */
return 0;
+
default:
+ /* But don't write to any other formats... */
return WTAP_ERR_UNSUPPORTED_ENCAP;
}
}
/*****************************************/
/* Write a single packet out to the file */
/*****************************************/
-gboolean catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
+
+static gboolean
+catapult_dct2000_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
const union wtap_pseudo_header *pseudo_header,
- const guchar *pd, int *err _U_)
+ const guint8 *pd, int *err)
{
guint32 n;
line_prefix_info_t *prefix = NULL;
gchar time_string[16];
+ gboolean is_comment;
+ dct2000_dump_t *dct2000;
/******************************************************/
- /* Look up the file_externals structure for this file */
+ /* Get the file_externals structure for this file */
/* Find wtap external structure for this wtap */
dct2000_file_externals_t *file_externals =
- (dct2000_file_externals_t*)g_hash_table_lookup(file_externals_table,
- pseudo_header->dct2000.wth);
+ (dct2000_file_externals_t*)pseudo_header->dct2000.wth->priv;
- if (wdh->dump.dct2000 == NULL)
- {
- /* Allocate the dct2000-specific dump structure */
- wdh->dump.dct2000 = g_malloc(sizeof(catapult_dct2000_t));
+ dct2000 = (dct2000_dump_t *)wdh->priv;
+ if (dct2000 == NULL) {
/* Write out saved first line */
- fwrite(file_externals->firstline, 1, file_externals->firstline_length, wdh->fh);
- fwrite("\n", 1, 1, wdh->fh);
+ if (!wtap_dump_file_write(wdh, file_externals->firstline,
+ file_externals->firstline_length, err)) {
+ return FALSE;
+ }
+ if (!wtap_dump_file_write(wdh, "\n", 1, err)) {
+ return FALSE;
+ }
/* Also write out saved second line with timestamp corresponding to the
opening time of the log.
*/
- fwrite(file_externals->secondline, 1, file_externals->secondline_length, wdh->fh);
- fwrite("\n", 1, 1, wdh->fh);
+ if (!wtap_dump_file_write(wdh, file_externals->secondline,
+ file_externals->secondline_length, err)) {
+ return FALSE;
+ }
+ if (!wtap_dump_file_write(wdh, "\n", 1, err)) {
+ return FALSE;
+ }
/* Allocate the dct2000-specific dump structure */
- wdh->dump.dct2000 = g_malloc(sizeof(catapult_dct2000_t));
+ dct2000 = (dct2000_dump_t *)g_malloc(sizeof(dct2000_dump_t));
+ wdh->priv = (void *)dct2000;
/* Copy time of beginning of file */
- wdh->dump.dct2000->start_time.secs =
- pseudo_header->dct2000.wth->capture.catapult_dct2000->start_secs;
- wdh->dump.dct2000->start_time.nsecs =
- (pseudo_header->dct2000.wth->capture.catapult_dct2000->start_usecs * 1000);
+ dct2000->start_time.secs = file_externals->start_secs;
+ dct2000->start_time.nsecs =
+ (file_externals->start_usecs * 1000);
/* Set flag do don't write header out again */
- wdh->dump.dct2000->first_packet_written = TRUE;
+ dct2000->first_packet_written = TRUE;
}
/* 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);
+ if (!wtap_dump_file_write(wdh, prefix->before_time,
+ strlen(prefix->before_time), err)) {
+ return FALSE;
+ }
+
+ /* Can infer from prefix if this is a comment (whose payload is displayed differently) */
+ is_comment = (strstr(prefix->before_time, "/////") != NULL);
/* Calculate time of this packet to write, relative to start of dump */
- if (phdr->ts.nsecs >= wdh->dump.dct2000->start_time.nsecs)
- {
+ if (phdr->ts.nsecs >= dct2000->start_time.nsecs) {
g_snprintf(time_string, 16, "%ld.%04d",
- (long)(phdr->ts.secs - wdh->dump.dct2000->start_time.secs),
- (phdr->ts.nsecs - wdh->dump.dct2000->start_time.nsecs) / 100000);
+ (long)(phdr->ts.secs - dct2000->start_time.secs),
+ (phdr->ts.nsecs - dct2000->start_time.nsecs) / 100000);
}
- else
- {
+ else {
g_snprintf(time_string, 16, "%ld.%04u",
- (long)(phdr->ts.secs - wdh->dump.dct2000->start_time.secs-1),
- ((1000000000 + (phdr->ts.nsecs / 100000)) - (wdh->dump.dct2000->start_time.nsecs / 100000)) % 10000);
+ (long)(phdr->ts.secs - dct2000->start_time.secs-1),
+ ((1000000000 + (phdr->ts.nsecs / 100000)) - (dct2000->start_time.nsecs / 100000)) % 10000);
}
/* Write out the calculated timestamp */
- fwrite(time_string, 1, strlen(time_string), wdh->fh);
+ if (!wtap_dump_file_write(wdh, time_string, strlen(time_string), err)) {
+ return FALSE;
+ }
/* 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) {
+ if (!wtap_dump_file_write(wdh, " l ", strlen(" l "), err)) {
+ return FALSE;
+ }
+ }
+ else {
+ if (!wtap_dump_file_write(wdh, prefix->after_time,
+ strlen(prefix->after_time), err)) {
+ return FALSE;
+ }
+ }
/****************************************************************/
for (; pd[n] != '\0'; n++);
n++;
+ /* Outhdr (as string) */
+ for (; pd[n] != '\0'; n++);
+ n++;
+
/* Direction & encap */
n += 2;
/**************************************/
/* Remainder is encapsulated protocol */
- fwrite("$", 1, 1, wdh->fh);
+ if (!wtap_dump_file_write(wdh, "$", 1, err)) {
+ return FALSE;
+ }
- /* Each binary byte is written out as 2 hex string chars */
- for (; n < phdr->len; n++)
- {
- gchar c[2];
- c[0] = char_from_hex((guchar)(pd[n] >> 4));
- c[1] = char_from_hex((guchar)(pd[n] & 0x0f));
+ if (!is_comment) {
+ /* Each binary byte is written out as 2 hex string chars */
+ for (; n < phdr->len; n++) {
+ gchar c[2];
+ c[0] = char_from_hex((guint8)(pd[n] >> 4));
+ c[1] = char_from_hex((guint8)(pd[n] & 0x0f));
- /* Write both hex chars of byte together */
- fwrite(c, 1, 2, wdh->fh);
+ /* Write both hex chars of byte together */
+ if (!wtap_dump_file_write(wdh, c, 2, err)) {
+ return FALSE;
+ }
+ }
+ }
+ else {
+ for (; n < phdr->len; n++) {
+ char c[1];
+ c[0] = pd[n];
+
+ /* Write both hex chars of byte together */
+ if (!wtap_dump_file_write(wdh, c, 1, err)) {
+ return FALSE;
+ }
+ }
}
/* End the line */
- fwrite("\n", 1, 1, wdh->fh);
-
- return TRUE;
-}
-
+ if (!wtap_dump_file_write(wdh, "\n", 1, err)) {
+ return FALSE;
+ }
-/******************************************************/
-/* Close a file we've been writing to. */
-/******************************************************/
-static gboolean catapult_dct2000_dump_close(wtap_dumper *wdh _U_, int *err _U_)
-{
return TRUE;
}
-
-
/****************************/
/* Private helper functions */
/****************************/
/**********************************************************************/
/* Read a new line from the file, starting at offset. */
-/* - writes data to static var linebuff */
+/* - writes data to its argument linebuff */
/* - 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)
+static gboolean
+read_new_line(FILE_T fh, gint64 *offset, gint *length,
+ gchar *linebuff, size_t linebuffsize)
{
- char *result;
-
/* Read in a line */
- result = file_gets(linebuff, MAX_LINE_LENGTH, fh);
- if (result == NULL)
- {
- /* No characters found */
+ gint64 pos_before = file_tell(fh);
+ char *result = file_gets(linebuff, (int)linebuffsize - 1, fh);
+ if (result == NULL) {
+ /* No characters found, or error */
return FALSE;
}
- /* Set length and offset.. */
- *length = strlen(linebuff);
+ /* Set length (avoiding strlen()) and offset.. */
+ *length = (gint)(file_tell(fh) - pos_before);
*offset = *offset + *length;
/* ...but don't want to include newline in line length */
- if (linebuff[*length-1] == '\n')
- {
+ if (linebuff[*length-1] == '\n') {
linebuff[*length-1] = '\0';
*length = *length - 1;
}
/* - data position and length */
/* Return TRUE if this packet looks valid and can be displayed */
/**********************************************************************/
-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)
+static gboolean
+parse_line(gchar *linebuff, 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, int *is_comment,
+ gchar *aal_header_chars,
+ gchar *context_name, guint8 *context_portp,
+ gchar *protocol_name, gchar *variant_name,
+ gchar *outhdr_name)
{
int n = 0;
- int port_digits = 0;
+ int port_digits;
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;
+ *is_comment = 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] != '_'))
- {
+ for (n=0; (linebuff[n] != '.') && (n < MAX_CONTEXT_NAME) && (n+1 < line_length); n++) {
+ if (linebuff[n] == '/') {
+ context_name[n] = '\0';
+
+ /* If not a comment (/////), not a valid line */
+ if (strncmp(linebuff+n, "/////", 5) != 0) {
+ return FALSE;
+ }
+
+ /* There is no variant, outhdr, etc. Set protocol to be a comment */
+ g_snprintf(protocol_name, MAX_PROTOCOL_NAME, "comment");
+ *is_comment = TRUE;
+ break;
+ }
+ if (!isalnum((guchar)linebuff[n]) && (linebuff[n] != '_') && (linebuff[n] != '-')) {
return FALSE;
}
context_name[n] = linebuff[n];
}
- if (n == MAX_CONTEXT_NAME || (n+1 >= line_length))
- {
+ if (n == MAX_CONTEXT_NAME || (n+1 >= line_length)) {
return FALSE;
}
- /* '.' must follow context name */
- if (linebuff[n] != '.')
- {
- return FALSE;
- }
- context_name[n] = '\0';
- /* Skip it */
- n++;
+ /* Reset strings (that won't be set by comments) */
+ variant_name[0] = '\0';
+ outhdr_name[0] = '\0';
+ port_number_string[0] = '\0';
+
+ if (!(*is_comment)) {
+ /* '.' must follow context name */
+ if (linebuff[n] != '.') {
+ return FALSE;
+ }
+ context_name[n] = '\0';
+ /* Skip it */
+ n++;
+ /* Now read port number */
+ for (port_digits = 0;
+ (linebuff[n] != '/') && (port_digits <= MAX_PORT_DIGITS) && (n+1 < line_length);
+ n++, port_digits++) {
- /* Now read port number */
- for (port_digits = 0;
- (linebuff[n] != '/') && (port_digits <= MAX_PORT_DIGITS) && (n+1 < line_length);
- n++, port_digits++)
- {
- if (!isdigit(linebuff[n]))
+ if (!isdigit((guchar)linebuff[n])) {
+ return FALSE;
+ }
+ port_number_string[port_digits] = linebuff[n];
+ }
+ if (port_digits > MAX_PORT_DIGITS || (n+1 >= line_length)) {
+ return FALSE;
+ }
+
+ /* Slash char must follow port number */
+ if (linebuff[n] != '/')
{
return FALSE;
}
- port_number_string[port_digits] = linebuff[n];
- }
- if (port_digits > MAX_PORT_DIGITS || (n+1 >= line_length))
- {
- return FALSE;
- }
+ port_number_string[port_digits] = '\0';
+ *context_portp = atoi(port_number_string);
+ /* Skip it */
+ n++;
- /* Slash char must follow port number */
- if (linebuff[n] != '/')
- {
- return FALSE;
- }
- port_number_string[port_digits] = '\0';
- context_port = atoi(port_number_string);
- /* Skip it */
- n++;
+ /* Now for the protocol name */
+ for (protocol_chars = 0;
+ (linebuff[n] != '/') && (protocol_chars < MAX_PROTOCOL_NAME) && (n < line_length);
+ n++, protocol_chars++) {
+ if (!isalnum((guchar)linebuff[n]) && linebuff[n] != '_') {
+ return FALSE;
+ }
+ protocol_name[protocol_chars] = linebuff[n];
+ }
+ if (protocol_chars == MAX_PROTOCOL_NAME || n >= line_length) {
+ /* If doesn't fit, fail rather than truncate */
+ return FALSE;
+ }
+ protocol_name[protocol_chars] = '\0';
- /* Now for the protocol name */
- for (protocol_chars = 0;
- (linebuff[n] != '/') && (protocol_chars < MAX_PROTOCOL_NAME) && (n < line_length);
- n++, protocol_chars++)
- {
- if (!isalnum(linebuff[n]) && linebuff[n] != '_')
- {
+ /* Slash char must follow protocol name */
+ if (linebuff[n] != '/') {
return FALSE;
}
- protocol_name[protocol_chars] = linebuff[n];
- }
- if (protocol_chars == MAX_PROTOCOL_NAME || n >= line_length)
- {
- /* If doesn't fit, fail rather than truncate */
- return FALSE;
- }
- protocol_name[protocol_chars] = '\0';
+ /* Skip it */
+ n++;
- /* Slash char must follow protocol name */
- if (linebuff[n] != '/')
- {
- return FALSE;
+
+ /* Following the / is the variant number. No digits indicate 1 */
+ for (variant_digits = 0;
+ (isdigit((guchar)linebuff[n])) && (variant_digits <= MAX_VARIANT_DIGITS) && (n+1 < line_length);
+ n++, variant_digits++) {
+
+ if (!isdigit((guchar)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 {
+ g_strlcpy(variant_name, "1", MAX_VARIANT_DIGITS+1);
+ }
+
+
+ /* Outheader values may follow */
+ outhdr_name[0] = '\0';
+ if (linebuff[n] == ',') {
+ /* Skip , */
+ n++;
+
+ for (outhdr_chars = 0;
+ (isdigit((guchar)linebuff[n]) || linebuff[n] == ',') &&
+ (outhdr_chars <= MAX_OUTHDR_NAME) && (n+1 < line_length);
+ n++, outhdr_chars++) {
+
+ if (!isdigit((guchar)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';
+ }
}
- /* Skip it */
- n++;
/******************************************************************/
/* 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) ||
+ (strcmp(protocol_name, "igmp") == 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))
- {
+ (strcmp(protocol_name, "fp_r6") == 0) ||
+ (strcmp(protocol_name, "fp_r7") == 0) ||
+ (strcmp(protocol_name, "fp_r8") == 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)
- {
+ if (strcmp(protocol_name, "ppp") == 0) {
*encap = WTAP_ENCAP_PPP;
}
else
- if (strcmp(protocol_name, "isdn_l3") == 0)
- {
- /* Despite the name, this does seem to correspond to L2... */
+ if (strcmp(protocol_name, "isdn_l3") == 0) {
+ /* TODO: find out what this byte means... */
+ skip_first_byte = TRUE;
*encap = WTAP_ENCAP_ISDN;
}
else
- if (strcmp(protocol_name, "ethernet") == 0)
- {
+ if (strcmp(protocol_name, "isdn_l2") == 0) {
+ *encap = WTAP_ENCAP_ISDN;
+ }
+ else
+ if (strcmp(protocol_name, "ethernet") == 0) {
*encap = WTAP_ENCAP_ETHERNET;
}
else
if ((strcmp(protocol_name, "saalnni_sscop") == 0) ||
- (strcmp(protocol_name, "saaluni_sscop") == 0))
- {
+ (strcmp(protocol_name, "saaluni_sscop") == 0)) {
+
*encap = DCT2000_ENCAP_SSCOP;
}
else
- if (strcmp(protocol_name, "frelay_l2") == 0)
- {
+ if (strcmp(protocol_name, "frelay_l2") == 0) {
*encap = WTAP_ENCAP_FRELAY;
}
else
- if (strcmp(protocol_name, "ss7_mtp2") == 0)
- {
+ if (strcmp(protocol_name, "ss7_mtp2") == 0) {
*encap = DCT2000_ENCAP_MTP2;
}
else
- {
- /* 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;
- }
- }
-
+ if ((strcmp(protocol_name, "nbap") == 0) ||
+ (strcmp(protocol_name, "nbap_r4") == 0) ||
+ (strncmp(protocol_name, "nbap_sscfuni", strlen("nbap_sscfuni")) == 0)) {
- /* 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];
+ /* The entire message in these cases is nbap, so use an encap value. */
+ *encap = DCT2000_ENCAP_NBAP;
}
- if (variant_digits > MAX_VARIANT_DIGITS || (n+1 >= line_length))
- {
- return FALSE;
- }
- if (variant_digits > 0)
- {
- variant_name[variant_digits] = '\0';
- }
- else
- {
- strcpy(variant_name, "1");
+ else {
+ /* 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;
}
/* Find separate ATM header if necessary */
- if (atm_header_present)
- {
+ if (atm_header_present) {
int header_chars_seen = 0;
/* Scan ahead to the next $ */
for (; (linebuff[n] != '$') && (n+1 < line_length); n++);
/* Skip it */
n++;
- if (n+1 >= line_length)
- {
+ if (n+1 >= line_length) {
return FALSE;
}
/* Read consecutive hex chars into atm header buffer */
for (;
- (isalnum(linebuff[n]) &&
+ ((linebuff[n] >= '0') && (linebuff[n] <= '?') &&
(n < line_length) &&
(header_chars_seen < AAL_HEADER_CHARS));
- n++, header_chars_seen++)
- {
+ n++, header_chars_seen++) {
+
aal_header_chars[header_chars_seen] = linebuff[n];
+ /* Next 6 characters after '9' are mapped to a->f */
+ if (!isdigit((guchar)linebuff[n])) {
+ aal_header_chars[header_chars_seen] = 'a' + (linebuff[n] - '9') -1;
+ }
}
- if (header_chars_seen != AAL_HEADER_CHARS || n >= line_length)
- {
+ if (header_chars_seen != AAL_HEADER_CHARS || n >= line_length) {
return FALSE;
}
}
+ /* Skip next '/' */
+ n++;
- /* Scan ahead to the next space */
- for (; (linebuff[n] != ' ') && (n+1 < line_length); n++);
- if (n+1 >= line_length)
- {
- return FALSE;
+ /* If there is a number, skip all info to next '/'.
+ TODO: for IP encapsulation, should store PDCP ueid, drb in pseudo info
+ and display dct2000 dissector... */
+ if (isdigit(linebuff[n])) {
+ while ((n+1 < line_length) && linebuff[n] != '/') {
+ n++;
+ }
}
- /* Skip it */
- n++;
- /* Next character gives direction of message (must be 's' or 'r') */
- if (linebuff[n] == 's')
- {
- *direction = sent;
+ /* Skip '/' */
+ while ((n+1 < line_length) && linebuff[n] == '/') {
+ n++;
}
- else
- if (linebuff[n] == 'r')
- {
- *direction = received;
+
+ /* Skip a space that may happen here */
+ if ((n+1 < line_length) && linebuff[n] == ' ') {
+ n++;
}
- else
- {
- return FALSE;
+
+ /* Next character gives direction of message (must be 's' or 'r') */
+ if (!(*is_comment)) {
+ if (linebuff[n] == 's') {
+ *direction = sent;
+ }
+ else
+ if (linebuff[n] == 'r') {
+ *direction = received;
+ }
+ else {
+ return FALSE;
+ }
+ /* Skip it */
+ n++;
+ }
+ else {
+ *direction = sent;
}
/* 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++);
- if (n >= line_length)
- {
+ /* This will involve skipping " tm " */
+
+ for (; ((linebuff[n] != 't') || (linebuff[n+1] != 'm')) && (n+1 < line_length); n++);
+ if (n >= line_length) {
+ return FALSE;
+ }
+
+ for (; !isdigit((guchar)linebuff[n]) && (n < line_length); n++);
+ if (n >= line_length) {
return FALSE;
}
(linebuff[n] != '.') &&
(seconds_chars <= MAX_SECONDS_CHARS) &&
(n < line_length);
- n++, seconds_chars++)
- {
- if (!isdigit(linebuff[n]))
- {
+ n++, seconds_chars++) {
+
+ if (!isdigit((guchar)linebuff[n])) {
/* Found a non-digit before decimal point. Fail */
return FALSE;
}
seconds_buff[seconds_chars] = linebuff[n];
}
- if (seconds_chars > MAX_SECONDS_CHARS || n >= line_length)
- {
+ if (seconds_chars > MAX_SECONDS_CHARS || n >= line_length) {
/* 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);
/* The decimal point must follow the last of the seconds digits */
- if (linebuff[n] != '.')
- {
+ if (linebuff[n] != '.') {
return FALSE;
}
/* Skip it */
(linebuff[n] != ' ') &&
(subsecond_decimals_chars <= MAX_SUBSECOND_DECIMALS) &&
(n < line_length);
- n++, subsecond_decimals_chars++)
- {
- if (!isdigit(linebuff[n]))
- {
+ n++, subsecond_decimals_chars++) {
+
+ if (!isdigit((guchar)linebuff[n])) {
return FALSE;
}
subsecond_decimals_buff[subsecond_decimals_chars] = linebuff[n];
}
- if (subsecond_decimals_chars > MAX_SUBSECOND_DECIMALS || n >= line_length)
- {
+ if (subsecond_decimals_chars > MAX_SUBSECOND_DECIMALS || n >= line_length) {
/* More numbers than expected - give up */
return FALSE;
}
*useconds = atoi(subsecond_decimals_buff) * 100;
/* Space character must follow end of timestamp */
- if (linebuff[n] != ' ')
- {
+ if (linebuff[n] != ' ') {
return FALSE;
}
*after_time_offset = n;
/* Now skip ahead to find start of data (marked by '$') */
- for (; (linebuff[n] != '$') && (n+1 < line_length); n++);
- if (n+1 >= line_length)
- {
+ /* Want to avoid matching with normal sprint command output at the moment... */
+ for (; (linebuff[n] != '$') && (linebuff[n] != '\'') && (n+1 < line_length); n++);
+ if ((linebuff[n] == '\'') || (n+1 >= line_length)) {
return FALSE;
}
/* Skip it */
/* 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;
}
/*****************************************************************/
/* Write the stub info to the data buffer while reading a packet */
/*****************************************************************/
-int write_stub_header(guchar *frame_buffer, char *timestamp_string,
- packet_direction_t direction, int encap)
+static int
+write_stub_header(guint8 *frame_buffer, char *timestamp_string,
+ packet_direction_t direction, int encap,
+ gchar *context_name, guint8 context_port,
+ gchar *protocol_name, gchar *variant_name,
+ gchar *outhdr_name)
{
int stub_offset = 0;
-
- strcpy((char*)frame_buffer, context_name);
- stub_offset += (strlen(context_name) + 1);
+
+ g_strlcpy((char*)frame_buffer, context_name, MAX_CONTEXT_NAME+1);
+ stub_offset += (int)(strlen(context_name) + 1);
/* Context port number */
frame_buffer[stub_offset] = context_port;
stub_offset++;
/* Timestamp within file */
- strcpy((char*)&frame_buffer[stub_offset], timestamp_string);
- stub_offset += (strlen(timestamp_string) + 1);
+ g_strlcpy((char*)&frame_buffer[stub_offset], timestamp_string, MAX_TIMESTAMP_LEN+1);
+ stub_offset += (int)(strlen(timestamp_string) + 1);
/* Protocol name */
- strcpy((char*)&frame_buffer[stub_offset], protocol_name);
- stub_offset += (strlen(protocol_name) + 1);
+ g_strlcpy((char*)&frame_buffer[stub_offset], protocol_name, MAX_PROTOCOL_NAME+1);
+ stub_offset += (int)(strlen(protocol_name) + 1);
- /* Protocol variant number */
- strcpy((void*)&frame_buffer[stub_offset], variant_name);
- stub_offset += (strlen(variant_name) + 1);
+ /* Protocol variant number (as string) */
+ g_strlcpy((void*)&frame_buffer[stub_offset], variant_name, MAX_VARIANT_DIGITS+1);
+ stub_offset += (int)(strlen(variant_name) + 1);
+
+ /* Outhdr */
+ g_strlcpy((char*)&frame_buffer[stub_offset], outhdr_name, MAX_OUTHDR_NAME+1);
+ stub_offset += (int)(strlen(outhdr_name) + 1);
/* Direction */
frame_buffer[stub_offset] = direction;
/* Encap */
frame_buffer[stub_offset] = (guint8)encap;
stub_offset++;
-
+
return stub_offset;
}
/**************************************************************/
/* Set pseudo-header info depending upon packet encapsulation */
/**************************************************************/
-void set_pseudo_header_info(wtap *wth,
- int pkt_encap,
- long file_offset,
- union wtap_pseudo_header *pseudo_header,
- gint length,
- packet_direction_t direction)
+static void
+set_pseudo_header_info(wtap *wth,
+ int pkt_encap,
+ gint64 file_offset,
+ union wtap_pseudo_header *pseudo_header,
+ packet_direction_t direction,
+ gchar *aal_header_chars)
{
pseudo_header->dct2000.seek_off = file_offset;
pseudo_header->dct2000.wth = wth;
- switch (pkt_encap)
- {
+ switch (pkt_encap) {
case WTAP_ENCAP_ATM_PDUS_UNTRUNCATED:
- set_aal_info(pseudo_header, length, direction);
+ set_aal_info(pseudo_header, direction, aal_header_chars);
break;
case WTAP_ENCAP_ISDN:
set_isdn_info(pseudo_header, direction);
/*********************************************/
/* Fill in atm pseudo-header with known info */
/*********************************************/
-void set_aal_info(union wtap_pseudo_header *pseudo_header, gint length,
- packet_direction_t direction)
+static void
+set_aal_info(union wtap_pseudo_header *pseudo_header,
+ packet_direction_t direction,
+ gchar *aal_header_chars)
{
/* 'aal_head_chars' has this format (for AAL2 at least):
Global Flow Control (4 bits) | VPI (8 bits) | VCI (16 bits) |
/* 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) */
pseudo_header->dct2000.inner_pseudo_header.atm.vpi =
- ((hex_from_char(aal_header_chars[1]) << 4) |
- hex_from_char(aal_header_chars[2]));
+ hex_byte_from_chars(aal_header_chars+1);
/* vci is next 16 bits */
pseudo_header->dct2000.inner_pseudo_header.atm.vci =
/* 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((guchar)aal_header_chars[11])) {
+ pseudo_header->dct2000.inner_pseudo_header.atm.aal2_cid =
+ hex_byte_from_chars(aal_header_chars+10);
+ }
+ else {
+ pseudo_header->dct2000.inner_pseudo_header.atm.aal2_cid =
+ (int)aal_header_chars[11] - '0';
+ }
}
/**********************************************/
/* Fill in isdn pseudo-header with known info */
/**********************************************/
-void set_isdn_info(union wtap_pseudo_header *pseudo_header,
+static void
+set_isdn_info(union wtap_pseudo_header *pseudo_header,
packet_direction_t direction)
{
/* This field is used to set the 'Source' and 'Destination' columns to
/*********************************************/
/* Fill in ppp pseudo-header with known info */
/*********************************************/
-static void set_ppp_info(union wtap_pseudo_header *pseudo_header,
+static void
+set_ppp_info(union wtap_pseudo_header *pseudo_header,
packet_direction_t direction)
{
/* Set direction. */
/********************************************************/
/* Return hex nibble equivalent of hex string character */
/********************************************************/
-guchar hex_from_char(gchar c)
+static guint8
+hex_from_char(gchar c)
{
- if ((c >= '0') && (c <= '9'))
- {
+ if ((c >= '0') && (c <= '9')) {
return c - '0';
}
- if ((c >= 'a') && (c <= 'f'))
- {
+ if ((c >= 'a') && (c <= 'f')) {
return 0x0a + (c - 'a');
}
return 0xff;
}
+/* Extract and return a byte value from 2 ascii hex chars, starting from the given pointer */
+static guint8
+hex_byte_from_chars(gchar *c)
+{
+ static guchar hex_char_array[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ /* Populate lookup table first time */
+ static guint8 tableValues[255][255];
+ static gint tableSet = FALSE;
+ if (!tableSet) {
+ gint i, j;
+ for (i=0; i < 16; i++) {
+ for (j=0; j < 16; j++) {
+ tableValues[hex_char_array[i]][hex_char_array[j]] = i*16 + j;
+ }
+ }
+
+ tableSet = TRUE;
+ }
+
+ /* Return value from quick table lookup */
+ return tableValues[(unsigned char)c[0]][(unsigned char)c[1]];
+}
+
+
/********************************************************/
/* Return character corresponding to hex nibble value */
/********************************************************/
-gchar char_from_hex(guchar hex)
+static gchar
+char_from_hex(guint8 hex)
{
static char hex_lookup[16] =
{ '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
- if (hex > 15)
- {
+ if (hex > 15) {
return '?';
}
return hex_lookup[hex];
}
-
-/********************************************/
-/* Equality test for line-prefix hash table */
-/********************************************/
-gint prefix_equal(gconstpointer v, gconstpointer v2)
+/***********************************************/
+/* Equality test for packet prefix hash tables */
+/***********************************************/
+static gint
+packet_offset_equal(gconstpointer v, gconstpointer v2)
{
- return (v == 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)
+static 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);
}
/* Set secs and usecs as output */
/* Return FALSE if no valid time can be read */
/************************************************************************/
-gboolean get_file_time_stamp(time_t *secs, guint32 *usecs)
+static gboolean
+get_file_time_stamp(gchar *linebuff, time_t *secs, guint32 *usecs)
{
int n;
struct tm tm;
int scan_found;
/* If line longer than expected, file is probably not correctly formatted */
- if (strlen(linebuff) > MAX_TIMESTAMP_LINE_LENGTH)
- {
+ if (strlen(linebuff) > MAX_TIMESTAMP_LINE_LENGTH) {
return FALSE;
}
/**************************************************************/
/* First is month. Read until get a space following the month */
- for (n=0; (linebuff[n] != ' ') && (n < MAX_MONTH_LETTERS); n++)
- {
+ for (n=0; (linebuff[n] != ' ') && (n < MAX_MONTH_LETTERS); n++) {
month[n] = linebuff[n];
}
month[n] = '\0';
else if (strcmp(month, "October" ) == 0) tm.tm_mon = 9;
else if (strcmp(month, "November" ) == 0) tm.tm_mon = 10;
else if (strcmp(month, "December" ) == 0) tm.tm_mon = 11;
- else
- {
+ else {
/* Give up if not found a properly-formatted date */
return FALSE;
}
/********************************************************/
/* Scan for remaining numerical fields */
- scan_found = sscanf(linebuff+n, "%d, %d %d:%d:%d.%u",
+ scan_found = sscanf(linebuff+n, "%2d, %4d %2d:%2d:%2d.%4u",
&day, &year, &hour, &minute, &second, usecs);
- if (scan_found != 6)
- {
+ if (scan_found != 6) {
/* Give up if not all found */
return FALSE;
}
}
/* Free the data allocated inside a line_prefix_info_t */
-gboolean free_line_prefix_info(gpointer key _U_, gpointer value,
+static 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);