aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap
diff options
context:
space:
mode:
Diffstat (limited to 'wiretap')
-rw-r--r--wiretap/Makefile.common2
-rw-r--r--wiretap/dct3trace.c390
-rw-r--r--wiretap/dct3trace.h28
-rw-r--r--wiretap/file_access.c7
-rw-r--r--wiretap/wtap.c3
-rw-r--r--wiretap/wtap.h25
6 files changed, 454 insertions, 1 deletions
diff --git a/wiretap/Makefile.common b/wiretap/Makefile.common
index e56a3bf3a2..68c411f1e8 100644
--- a/wiretap/Makefile.common
+++ b/wiretap/Makefile.common
@@ -41,6 +41,7 @@ NONGENERATED_C_FILES = \
cosine.c \
csids.c \
dbs-etherwatch.c \
+ dct3trace.c \
erf.c \
etherpeek.c \
eyesdn.c \
@@ -85,6 +86,7 @@ NONGENERATED_HEADER_FILES = \
cosine.h \
csids.h \
dbs-etherwatch.h \
+ dct3trace.h \
erf.h \
etherpeek.h \
eyesdn.h \
diff --git a/wiretap/dct3trace.c b/wiretap/dct3trace.c
new file mode 100644
index 0000000000..2697609696
--- /dev/null
+++ b/wiretap/dct3trace.c
@@ -0,0 +1,390 @@
+/* dct3trace.c
+ * Routines for reading signalling traces generated by Gammu (www.gammu.org)
+ * from Nokia DCT3 phones in Netmonitor mode.
+ *
+ * gammu --nokiadebug nhm5_587.txt v20-25,v18-19
+ *
+ * Duncan Salerno <duncan.salerno@googlemail.com>
+ *
+ * $Id$
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "wtap-int.h"
+#include "buffer.h"
+#include "dct3trace.h"
+#include "file_wrappers.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+
+/*
+ Example downlink data:
+
+<?xml version="1.0"?>
+<dump>
+<l1 direction="down" logicalchannel="96" physicalchannel="19" sequence="268116" error="0" timeshift="2992" bsic="22" data="31063F100DD0297A53E1020103C802398E0B2B2B2B2B2B" >
+<l2 data="063F100DD0297A53E1020103" rest="C802398E0B2B2B2B2B2B" >
+</l2>
+</l1>
+</dump>
+
+ Example uplink data (no raw L1):
+
+<?xml version="1.0"?>
+<dump>
+<l1 direction="up" logicalchannel="112" >
+<l2 type="U" subtype="Unknown" p="0" data="061500400000000000000000000000000000" >
+</l2>
+</l1>
+</dump>
+
+ */
+
+
+/* Magic text to check */
+static const char dct3trace_magic_line1[] = "<?xml version=\"1.0\"?>";
+static const char dct3trace_magic_line2[] = "<dump>";
+static const char dct3trace_magic_record_start[] = "<l1 ";
+static const char dct3trace_magic_record_end[] = "</l1>";
+static const char dct3trace_magic_l2_start[] = "<l2 ";
+static const char dct3trace_magic_l2_end[] = "</l2>";
+static const char dct3trace_magic_end[] = "</dump>";
+
+
+static gboolean dct3trace_read(wtap *wth, int *err, gchar **err_info,
+ gint64 *data_offset);
+static gboolean dct3trace_seek_read(wtap *wth, gint64 seek_off,
+ union wtap_pseudo_header *pseudo_header, guint8 *pd, int len,
+ int *err, gchar **err_info);
+
+/*
+ * Following 3 functions taken from gsmdecode-0.7bis, with permission - http://wiki.thc.org/gsm
+ */
+
+static int
+hc2b(unsigned char hex)
+{
+ hex = tolower(hex);
+ if ((hex >= '0') && (hex <= '9'))
+ return hex - '0';
+ if ((hex >= 'a') && (hex <= 'f'))
+ return hex - 'a' + 10;
+ return -1;
+}
+
+static int
+hex2bin(unsigned char *out, unsigned char *in)
+{
+ unsigned char *out_start = out;
+ unsigned char *end = in + strlen((char *)in);
+ int is_low = 0;
+ int c;
+
+ while (in < end)
+ {
+ c = hc2b(in[0]);
+ if (c < 0)
+ {
+ in++;
+ continue;
+ }
+ if (is_low == 0)
+ {
+ out[0] = c << 4;
+ is_low = 1;
+ } else {
+ out[0] |= (c & 0x0f);
+ is_low = 0;
+ out++;
+ }
+ in++;
+ }
+
+ return out - out_start;
+}
+
+static int
+xml_get_int(int *val, const unsigned char *str, const unsigned char *pattern)
+{
+ char *ptr;
+ char *start, *end;
+ char buf[32];
+
+ ptr = strstr((char *)str, (char *)pattern);
+ if (ptr == NULL)
+ return -1;
+ start = strchr(ptr, '"');
+ if (start == NULL)
+ return -2;
+ start++;
+ end = strchr(start, '"');
+ if (end == NULL)
+ return -3;
+
+ memcpy(buf, start, end - start);
+ buf[end - start] = '\0';
+ *val = atoi(buf);
+ return 0;
+}
+
+
+/* Look through the first part of a file to see if this is
+ * a DCT3 trace file.
+ *
+ * Returns TRUE if it is, FALSE if it isn't or if we get an I/O error;
+ * if we get an I/O error, "*err" will be set to a non-zero value.
+ */
+static gboolean dct3trace_check_file_type(wtap *wth, int *err)
+{
+ char line1[64], line2[64];
+
+ if (file_gets(line1, sizeof(line1), wth->fh) != NULL &&
+ file_gets(line2, sizeof(line2), wth->fh) != NULL)
+ {
+ /* Don't compare line endings */
+ if( strncmp(dct3trace_magic_line1, line1, strlen(dct3trace_magic_line1)) == 0 &&
+ strncmp(dct3trace_magic_line2, line2, strlen(dct3trace_magic_line2)) == 0)
+ {
+ return TRUE;
+ }
+ }
+ /* EOF or error. */
+ else
+ {
+ if (file_eof(wth->fh))
+ *err = 0;
+ else
+ *err = file_error(wth->fh);
+ }
+
+ return FALSE;
+}
+
+
+int dct3trace_open(wtap *wth, int *err, gchar **err_info _U_)
+{
+ /* Look for Gammu DCT3 trace header */
+ if (!dct3trace_check_file_type(wth, err))
+ {
+ if (*err == 0)
+ return 0;
+ else
+ return -1;
+ }
+
+ wth->data_offset = 0;
+ wth->file_encap = WTAP_ENCAP_GSM_UM;
+ wth->file_type = WTAP_FILE_DCT3TRACE;
+ wth->snapshot_length = 0; /* not known */
+ wth->subtype_read = dct3trace_read;
+ wth->subtype_seek_read = dct3trace_seek_read;
+ wth->tsprecision = WTAP_FILE_TSPREC_SEC;
+
+ return 1;
+}
+
+
+static gboolean dct3trace_get_packet(FILE *fh, union wtap_pseudo_header *pseudo_header,
+ unsigned char *buf, int *len, int *err, gchar **err_info)
+{
+ unsigned char line[1024];
+ gboolean have_data = FALSE;
+
+ while (file_gets(line, sizeof(line), fh) != NULL)
+ {
+ if( memcmp(dct3trace_magic_end, line, strlen(dct3trace_magic_end)) == 0 )
+ {
+ /* Return on end of file </dump> */
+ *err = 0;
+ return FALSE;
+ }
+ else if( memcmp(dct3trace_magic_record_end, line, strlen(dct3trace_magic_record_end)) == 0 )
+ {
+ /* Return on end of record </l1> */
+ if( have_data )
+ {
+ *err = 0;
+ return TRUE;
+ }
+ else
+ {
+ /* If not got any data return error */
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup_printf("dct3trace: record without data");
+ return FALSE;
+ }
+ }
+ else if( memcmp(dct3trace_magic_record_start, line, strlen(dct3trace_magic_record_start)) == 0 )
+ {
+ /* Parse L1 header <l1 ...>*/
+ int channel, tmp, ret = 0;
+ char *ptr;
+
+ pseudo_header->gsm_um.uplink = !strstr(line, "direction=\"down\"");
+ ret |= xml_get_int(&channel, line, "logicalchannel");
+
+ /* Parse downlink only fields */
+ if( !pseudo_header->gsm_um.uplink )
+ {
+ ret |= xml_get_int(&tmp, line, "physicalchannel");
+ pseudo_header->gsm_um.arfcn = tmp;
+ ret |= xml_get_int(&tmp, line, "sequence");
+ pseudo_header->gsm_um.tdma_frame = tmp;
+ ret |= xml_get_int(&tmp, line, "bsic");
+ pseudo_header->gsm_um.bsic = tmp;
+ ret |= xml_get_int(&tmp, line, "error");
+ pseudo_header->gsm_um.error = tmp;
+ ret |= xml_get_int(&tmp, line, "timeshift");
+ pseudo_header->gsm_um.timeshift = tmp;
+ }
+
+ if( ret != 0 )
+ {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup_printf("dct3trace: record missing mandatory attributes");
+ return FALSE;
+ }
+
+ switch( channel )
+ {
+ case 128: pseudo_header->gsm_um.channel = GSM_UM_CHANNEL_SDCCH; break;
+ case 112: pseudo_header->gsm_um.channel = GSM_UM_CHANNEL_SACCH; break;
+ case 176: pseudo_header->gsm_um.channel = GSM_UM_CHANNEL_FACCH; break;
+ case 96: pseudo_header->gsm_um.channel = GSM_UM_CHANNEL_CCCH; break;
+ case 80: pseudo_header->gsm_um.channel = GSM_UM_CHANNEL_BCCH; break;
+ default: pseudo_header->gsm_um.channel = GSM_UM_CHANNEL_UNKNOWN; break;
+ }
+
+ /* Read data (if have it) into buf */
+ ptr = strstr(line, "data=\"");
+ if( ptr )
+ {
+ have_data = TRUE; /* If has data... */
+ *len = hex2bin(buf, ptr+6);
+ }
+ }
+ else if( !have_data && memcmp(dct3trace_magic_l2_start, line, strlen(dct3trace_magic_l2_start)) == 0 )
+ {
+ /* For uplink packets we don't get the raw L1, so have to recreate it from the L2 */
+ /* Parse L2 header if didn't get data from L1 <l2 ...> */
+ int data_len = 0;
+ char *ptr = strstr(line, "data=\"");
+
+ if( !ptr )
+ {
+ continue;
+ }
+
+ have_data = TRUE;
+
+ if( pseudo_header->gsm_um.channel == GSM_UM_CHANNEL_SACCH || pseudo_header->gsm_um.channel == GSM_UM_CHANNEL_FACCH || pseudo_header->gsm_um.channel == GSM_UM_CHANNEL_SDCCH )
+ {
+ /* Add LAPDm B header */
+ memset(buf, 0x1, 2);
+ *len = 3;
+ }
+ else
+ {
+ /* Add LAPDm Bbis header */
+ *len = 1;
+ }
+ buf += *len;
+
+ data_len = hex2bin(buf, ptr+6);
+ *len += data_len;
+
+ /* Add LAPDm length byte */
+ *(buf - 1) = data_len << 2 | 0x1;
+ }
+ }
+
+ *err = file_error(fh);
+ if (*err == 0)
+ {
+ *err = WTAP_ERR_SHORT_READ;
+ }
+ return FALSE;
+}
+
+
+/* Find the next packet and parse it; called from wtap_read(). */
+static gboolean dct3trace_read(wtap *wth, int *err, gchar **err_info,
+ gint64 *data_offset)
+{
+ guint64 offset = file_tell(wth->fh);
+ int buf_len;
+ char buf[23];
+
+ if( !dct3trace_get_packet(wth->fh, &wth->pseudo_header, buf, &buf_len, err, err_info) )
+ {
+ return FALSE;
+ }
+
+ /* We've got a full packet! */
+ wth->phdr.ts.secs = 0;
+ wth->phdr.ts.nsecs = 0;
+ wth->phdr.caplen = buf_len;
+ wth->phdr.len = buf_len;
+
+ /* Make sure we have enough room for the packet */
+ buffer_assure_space(wth->frame_buffer, buf_len);
+ memcpy( buffer_start_ptr(wth->frame_buffer), buf, buf_len );
+
+ wth->data_offset = *data_offset = offset;
+
+ return TRUE;
+}
+
+
+/* Used to read packets in random-access fashion */
+static gboolean dct3trace_seek_read (wtap *wth, gint64 seek_off,
+ union wtap_pseudo_header *pseudo_header, guint8 *pd, int len,
+ int *err, gchar **err_info)
+{
+ int buf_len;
+ char buf[23];
+
+ if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
+ {
+ return FALSE;
+ }
+
+ if( !dct3trace_get_packet(wth->random_fh, pseudo_header, buf, &buf_len, err, err_info) )
+ {
+ return FALSE;
+ }
+
+ if( len != buf_len && len != -1 )
+ {
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup_printf("dct3trace: requested length %d doesn't match record length %d",
+ len, buf_len);
+ return FALSE;
+ }
+
+ memcpy( pd, buf, buf_len );
+ return TRUE;
+}
diff --git a/wiretap/dct3trace.h b/wiretap/dct3trace.h
new file mode 100644
index 0000000000..184d00394e
--- /dev/null
+++ b/wiretap/dct3trace.h
@@ -0,0 +1,28 @@
+/* dct3trace.h
+ *
+ * $Id$
+ *
+ * Wiretap Library
+ * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __W_DCT3TRACE_H__
+#define __W_DCT3TRACE_H__
+
+int dct3trace_open(wtap *wth, int *err, gchar **err_info);
+
+#endif
diff --git a/wiretap/file_access.c b/wiretap/file_access.c
index 60d1db407e..e69df0b46f 100644
--- a/wiretap/file_access.c
+++ b/wiretap/file_access.c
@@ -78,6 +78,7 @@
#include "pcapng.h"
#include "btsnoop.h"
#include "tnef.h"
+#include "dct3trace.h"
/* The open_file_* routines should return:
@@ -123,6 +124,7 @@ static wtap_open_routine_t open_routines_base[] = {
pcapng_open,
btsnoop_open,
tnef_open,
+ dct3trace_open,
/* Files that don't have magic bytes at a fixed location,
* but that instead require a heuristic of some sort to
* identify them. This includes the ASCII trace files that
@@ -590,7 +592,10 @@ static const struct file_type_info dump_open_table_base[] = {
{ NULL, NULL, NULL, NULL, FALSE, NULL, NULL },
/* WTAP_FILE_TNEF */
- { "Transport-Neutral Encapsulation Format", "tnef", "*.*", NULL, FALSE, NULL, NULL }
+ { "Transport-Neutral Encapsulation Format", "tnef", "*.*", NULL, FALSE, NULL, NULL },
+
+ /* WTAP_FILE_DCT3TRACE */
+ { "Gammu DCT3 trace", "dct3trace", "*.xml", NULL, FALSE, NULL, NULL }
};
gint wtap_num_file_types = sizeof(dump_open_table_base) / sizeof(struct file_type_info);
diff --git a/wiretap/wtap.c b/wiretap/wtap.c
index 1041e85de6..ab20d5b5b5 100644
--- a/wiretap/wtap.c
+++ b/wiretap/wtap.c
@@ -437,6 +437,9 @@ static struct encap_type_info encap_table_base[] = {
/* WTAP_ENCAP_USB_LINUX_MMAP */
{ "USB packets with Linux header and padding", "usb-linux-mmap" },
+
+ /* WTAP_ENCAP_GSM_UM */
+ { "GSM Um Interface", "gsm_um" }
};
gint wtap_num_encap_types = sizeof(encap_table_base) / sizeof(struct encap_type_info);
diff --git a/wiretap/wtap.h b/wiretap/wtap.h
index 7fe8b04c58..ab0237b3ac 100644
--- a/wiretap/wtap.h
+++ b/wiretap/wtap.h
@@ -206,6 +206,7 @@ extern "C" {
#define WTAP_ENCAP_IEEE802_15_4_NONASK_PHY 113
#define WTAP_ENCAP_TNEF 114
#define WTAP_ENCAP_USB_LINUX_MMAPPED 115
+#define WTAP_ENCAP_GSM_UM 116
#define WTAP_NUM_ENCAP_TYPES wtap_get_num_encap_types()
@@ -266,6 +267,7 @@ extern "C" {
#define WTAP_FILE_BTSNOOP 51
#define WTAP_FILE_X2E_XORAYA 52
#define WTAP_FILE_TNEF 53
+#define WTAP_FILE_DCT3TRACE 54
#define WTAP_NUM_FILE_TYPES wtap_get_num_file_types()
@@ -751,6 +753,28 @@ struct i2c_phdr {
guint8 bus;
guint32 flags;
};
+
+/* pseudo header for WTAP_ENCAP_GSM_UM */
+struct gsm_um_phdr {
+ gboolean uplink;
+ guint8 channel;
+ /* The following are only populated for downlink */
+ guint8 bsic;
+ guint16 arfcn;
+ guint32 tdma_frame;
+ guint8 error;
+ guint16 timeshift;
+};
+
+#define GSM_UM_CHANNEL_UNKNOWN 0
+#define GSM_UM_CHANNEL_BCCH 1
+#define GSM_UM_CHANNEL_SDCCH 2
+#define GSM_UM_CHANNEL_SACCH 3
+#define GSM_UM_CHANNEL_FACCH 4
+#define GSM_UM_CHANNEL_CCCH 5
+#define GSM_UM_CHANNEL_RACH 6
+#define GSM_UM_CHANNEL_AGCH 7
+#define GSM_UM_CHANNEL_PCH 8
union wtap_pseudo_header {
struct eth_phdr eth;
@@ -773,6 +797,7 @@ union wtap_pseudo_header {
struct bthci_phdr bthci;
struct l1event_phdr l1event;
struct i2c_phdr i2c;
+ struct gsm_um_phdr gsm_um;
};
struct wtap_nstime {