aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap/libpcap.c
diff options
context:
space:
mode:
Diffstat (limited to 'wiretap/libpcap.c')
-rw-r--r--wiretap/libpcap.c311
1 files changed, 302 insertions, 9 deletions
diff --git a/wiretap/libpcap.c b/wiretap/libpcap.c
index f7ef6f881f..09895d6cb8 100644
--- a/wiretap/libpcap.c
+++ b/wiretap/libpcap.c
@@ -35,6 +35,7 @@
#include "file_wrappers.h"
#include "buffer.h"
#include "atm.h"
+#include "erf.h"
#include "libpcap.h"
#ifdef HAVE_PCAP_H
@@ -143,6 +144,14 @@ static gboolean libpcap_read_lapd_pseudoheader(FILE_T fh,
union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
static gboolean libpcap_read_linux_usb_pseudoheader(wtap *wth, FILE_T fh,
union wtap_pseudo_header *pseudo_header, int *err);
+static gboolean libpcap_get_erf_pseudoheader(const guint8 *erf_hdr, struct wtap_pkthdr *whdr,
+ union wtap_pseudo_header *pseudo_header);
+static gboolean libpcap_read_erf_pseudoheader(FILE_T fh, struct wtap_pkthdr *whdr,
+ union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
+static gboolean libpcap_get_erf_subheader(const guint8 *erf_subhdr,
+ union wtap_pseudo_header *pseudo_header, guint * size);
+static gboolean libpcap_read_erf_subheader(FILE_T fh,
+ union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info _U_, guint * size);
static gboolean libpcap_read_rec_data(FILE_T fh, guchar *pd, int length,
int *err);
static void libpcap_close(wtap *wth);
@@ -429,7 +438,8 @@ static const struct {
{ 189, WTAP_ENCAP_USB_LINUX },
/* Per-Packet Information header */
{ 192, WTAP_ENCAP_PPI },
-
+ /* Endace Record File Encapsulation */
+ { 197, WTAP_ENCAP_ERF },
/*
* To repeat:
*
@@ -1174,7 +1184,7 @@ static gboolean libpcap_read(wtap *wth, int *err, gchar **err_info,
{
struct pcaprec_ss990915_hdr hdr;
guint packet_size;
- guint orig_size;
+ guint orig_size, size;
int bytes_read;
guchar fddi_padding[3];
@@ -1389,6 +1399,41 @@ static gboolean libpcap_read(wtap *wth, int *err, gchar **err_info,
packet_size -= sizeof (struct linux_usb_phdr);
wth->data_offset += sizeof (struct linux_usb_phdr);
break;
+
+ case WTAP_ENCAP_ERF:
+ if (packet_size < sizeof(struct erf_phdr) ) {
+ /*
+ * Uh-oh, the packet isn't big enough to even
+ * have a pseudo-header.
+ */
+ *err = WTAP_ERR_BAD_RECORD;
+ *err_info = g_strdup_printf("libpcap: ERF file has a %u-byte packet, too small to have even an ERF pseudo-header\n",
+ packet_size);
+ return FALSE;
+ }
+ if (!libpcap_read_erf_pseudoheader(wth->fh, &wth->phdr, &wth->pseudo_header,
+ err, err_info))
+ return FALSE; /* Read error */
+
+ /*
+ * Don't count the pseudo-header as part of the packet.
+ */
+ orig_size -= sizeof(struct erf_phdr);
+ packet_size -= sizeof(struct erf_phdr);
+ wth->data_offset += sizeof(struct erf_phdr);
+
+ if (!libpcap_read_erf_subheader(wth->fh, &wth->pseudo_header,
+ err, err_info, &size))
+ return FALSE; /* Read error */
+
+ /*
+ * Don't count the optional mc-header as part of the packet.
+ */
+ orig_size -= size;
+ packet_size -= size;
+ wth->data_offset += size;
+ break;
+
}
buffer_assure_space(wth->frame_buffer, packet_size);
@@ -1397,11 +1442,14 @@ static gboolean libpcap_read(wtap *wth, int *err, gchar **err_info,
return FALSE; /* Read error */
wth->data_offset += packet_size;
- wth->phdr.ts.secs = hdr.hdr.ts_sec;
- if(wth->tsprecision == WTAP_FILE_TSPREC_NSEC) {
- wth->phdr.ts.nsecs = hdr.hdr.ts_usec;
- } else {
- wth->phdr.ts.nsecs = hdr.hdr.ts_usec * 1000;
+ /* Update the Timestamp, if not already done */
+ if (wth->file_encap != WTAP_ENCAP_ERF) {
+ wth->phdr.ts.secs = hdr.hdr.ts_sec;
+ if(wth->tsprecision == WTAP_FILE_TSPREC_NSEC) {
+ wth->phdr.ts.nsecs = hdr.hdr.ts_usec;
+ } else {
+ wth->phdr.ts.nsecs = hdr.hdr.ts_usec * 1000;
+ }
}
wth->phdr.caplen = packet_size;
wth->phdr.len = orig_size;
@@ -1439,6 +1487,8 @@ libpcap_seek_read(wtap *wth, gint64 seek_off,
union wtap_pseudo_header *pseudo_header, guchar *pd, int length,
int *err, gchar **err_info)
{
+ guint size;
+
if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
return FALSE;
@@ -1514,6 +1564,20 @@ libpcap_seek_read(wtap *wth, gint64 seek_off,
pseudo_header, err))
return FALSE; /* Read error */
break;
+
+ case WTAP_ENCAP_ERF:
+ if (!libpcap_read_erf_pseudoheader(wth->random_fh, NULL, pseudo_header,
+ err, err_info)) {
+ /* Read error */
+ return FALSE;
+ }
+ /* check the optional Multi Channel header */
+ if (!libpcap_read_erf_subheader(wth->random_fh, pseudo_header,
+ err, err_info, &size)) {
+ /* Read error */
+ return FALSE;
+ }
+ break;
}
/*
@@ -1932,6 +1996,135 @@ libpcap_read_linux_usb_pseudoheader(wtap *wth, FILE_T fh,
}
static gboolean
+libpcap_get_erf_pseudoheader(const guint8 *erf_hdr, struct wtap_pkthdr *whdr,
+ union wtap_pseudo_header *pseudo_header)
+{
+ pseudo_header->erf.phdr.ts = pletohll(&erf_hdr[0]); /* timestamp */
+ pseudo_header->erf.phdr.type = erf_hdr[8];
+ pseudo_header->erf.phdr.flags = erf_hdr[9];
+ pseudo_header->erf.phdr.rlen = pntohs(&erf_hdr[10]);
+ pseudo_header->erf.phdr.lctr = pntohs(&erf_hdr[12]);
+ pseudo_header->erf.phdr.wlen = pntohs(&erf_hdr[14]);
+
+ /* The high 32 bits of the timestamp contain the integer number of seconds
+ * while the lower 32 bits contain the binary fraction of the second.
+ * This allows an ultimate resolution of 1/(2^32) seconds, or approximately 233 picoseconds */
+ if (whdr) {
+ guint64 ts = pseudo_header->erf.phdr.ts;
+ whdr->ts.secs = (guint32) (ts >> 32);
+ ts = ((ts & 0xffffffff) * 1000 * 1000 * 1000);
+ ts += (ts & 0x80000000) << 1; /* rounding */
+ whdr->ts.nsecs = ((guint32) (ts >> 32));
+ if ( whdr->ts.nsecs >= 1000000000) {
+ whdr->ts.nsecs -= 1000000000;
+ whdr->ts.secs += 1;
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
+libpcap_read_erf_pseudoheader(FILE_T fh, struct wtap_pkthdr *whdr,
+ union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info _U_)
+{
+ guint8 erf_hdr[sizeof(struct erf_phdr)];
+ int bytes_read;
+
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read = file_read(erf_hdr, 1, sizeof(struct erf_phdr), fh);
+ if (bytes_read != sizeof(struct erf_phdr)) {
+ *err = file_error(fh);
+ if (*err == 0)
+ *err = WTAP_ERR_SHORT_READ;
+ return FALSE;
+ }
+ return libpcap_get_erf_pseudoheader(erf_hdr, whdr, pseudo_header);
+}
+
+static gboolean
+libpcap_get_erf_subheader(const guint8 *erf_subhdr,
+ union wtap_pseudo_header *pseudo_header, guint * psize)
+{
+ *psize=0;
+ switch(pseudo_header->erf.phdr.type) {
+ case ERF_TYPE_MC_HDLC:
+ case ERF_TYPE_MC_RAW:
+ case ERF_TYPE_MC_ATM:
+ case ERF_TYPE_MC_RAW_CHANNEL:
+ case ERF_TYPE_MC_AAL5:
+ case ERF_TYPE_MC_AAL2:
+ case ERF_TYPE_COLOR_MC_HDLC_POS:
+ /* Extract the Multi Channel header to include it in the pseudo header part */
+ pseudo_header->erf.subhdr.mc_hdr = pntohl(&erf_subhdr[0]);
+ *psize = sizeof(erf_mc_header_t);
+ break;
+ case ERF_TYPE_ETH:
+ case ERF_TYPE_COLOR_ETH:
+ case ERF_TYPE_DSM_COLOR_ETH:
+ /* Extract the Ethernet additional header to include it in the pseudo header part */
+ pseudo_header->erf.subhdr.eth_hdr = pntohs(&erf_subhdr[0]);
+ *psize = sizeof(erf_eth_header_t);
+ break;
+ default:
+ /* No optional pseudo header for this ERF type */
+ break;
+ }
+ return TRUE;
+}
+
+/*
+ * If the type of record given in the pseudo header indicate the precense of a subheader
+ * then, read this optional subheader
+ */
+static gboolean
+libpcap_read_erf_subheader(FILE_T fh, union wtap_pseudo_header *pseudo_header,
+ int *err, gchar **err_info _U_, guint * psize)
+{
+ guint8 erf_subhdr[sizeof(union erf_subhdr)];
+ int bytes_read;
+
+ *psize=0;
+ switch(pseudo_header->erf.phdr.type) {
+ case ERF_TYPE_MC_HDLC:
+ case ERF_TYPE_MC_RAW:
+ case ERF_TYPE_MC_ATM:
+ case ERF_TYPE_MC_RAW_CHANNEL:
+ case ERF_TYPE_MC_AAL5:
+ case ERF_TYPE_MC_AAL2:
+ case ERF_TYPE_COLOR_MC_HDLC_POS:
+ /* Extract the Multi Channel header to include it in the pseudo header part */
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read = file_read(erf_subhdr, 1, sizeof(erf_mc_header_t), fh);
+ if (bytes_read != sizeof(erf_mc_header_t) ) {
+ *err = file_error(fh);
+ if (*err == 0)
+ *err = WTAP_ERR_SHORT_READ;
+ return FALSE;
+ }
+ *psize = sizeof(erf_mc_header_t);
+ break;
+ case ERF_TYPE_ETH:
+ case ERF_TYPE_COLOR_ETH:
+ case ERF_TYPE_DSM_COLOR_ETH:
+ /* Extract the Ethernet additional header to include it in the pseudo header part */
+ errno = WTAP_ERR_CANT_READ;
+ bytes_read = file_read(erf_subhdr, 1, sizeof(erf_eth_header_t), fh);
+ if (bytes_read != sizeof(erf_eth_header_t) ) {
+ *err = file_error(fh);
+ if (*err == 0)
+ *err = WTAP_ERR_SHORT_READ;
+ return FALSE;
+ }
+ *psize = sizeof(erf_eth_header_t);
+ break;
+ default:
+ /* No optional pseudo header for this ERF type */
+ break;
+ }
+ return libpcap_get_erf_subheader(erf_subhdr, pseudo_header, psize);
+}
+
+static gboolean
libpcap_read_rec_data(FILE_T fh, guchar *pd, int length, int *err)
{
int bytes_read;
@@ -2029,6 +2222,8 @@ wtap_process_pcap_packet(gint linktype, const struct pcap_pkthdr *phdr,
const guchar *pd, union wtap_pseudo_header *pseudo_header,
struct wtap_pkthdr *whdr, int *err)
{
+ guint size;
+
/* "phdr->ts" may not necessarily be a "struct timeval" - it may
be a "struct bpf_timeval", with member sizes wired to 32
bits - and we may go that way ourselves in the future, so
@@ -2159,7 +2354,38 @@ wtap_process_pcap_packet(gint linktype, const struct pcap_pkthdr *phdr,
whdr->len -= sizeof (struct linux_usb_phdr);
whdr->caplen -= sizeof (struct linux_usb_phdr);
pd += sizeof (struct linux_usb_phdr);
- break;
+ break;
+
+ case WTAP_ENCAP_ERF:
+ if (whdr->caplen < sizeof(struct erf_phdr) ) {
+ /*
+ * Uh-oh, the packet isn't big enough to even
+ * have a pseudo-header.
+ */
+ g_message("libpcap: ERF capture has a %u-byte packet, too small to have even an ERF pseudo-header\n",
+ whdr->caplen);
+ *err = WTAP_ERR_BAD_RECORD;
+ return NULL;
+ }
+ if (!libpcap_get_erf_pseudoheader(pd, whdr, pseudo_header))
+ return NULL;
+
+ /*
+ * Don't count the pseudo-header as part of the packet.
+ */
+ whdr->len -= sizeof(struct erf_phdr);
+ whdr->caplen -= sizeof(struct erf_phdr);
+ pd += sizeof(struct erf_phdr);
+
+ if (!libpcap_get_erf_subheader(pd, pseudo_header, &size))
+ return NULL;
+
+ /*
+ * Don't count the pseudo-header as part of the packet.
+ */
+ whdr->len -= size;
+ whdr->caplen -= size;
+ pd += size;
}
return pd;
}
@@ -2275,7 +2501,8 @@ static gboolean libpcap_dump(wtap_dumper *wdh,
guint8 irda_hdr[IRDA_SLL_LEN];
guint8 lapd_hdr[LAPD_SLL_LEN];
guint8 mtp2_hdr[MTP2_HDR_LEN];
- int hdrsize;
+ guint8 erf_hdr[ sizeof(struct erf_mc_phdr)];
+ int hdrsize, size;
switch (wdh->encap) {
@@ -2299,6 +2526,28 @@ static gboolean libpcap_dump(wtap_dumper *wdh,
hdrsize = sizeof (struct linux_usb_phdr);
break;
+ case WTAP_ENCAP_ERF:
+ hdrsize = sizeof (struct erf_phdr);
+ switch(pseudo_header->erf.phdr.type) {
+ case ERF_TYPE_MC_HDLC:
+ case ERF_TYPE_MC_RAW:
+ case ERF_TYPE_MC_ATM:
+ case ERF_TYPE_MC_RAW_CHANNEL:
+ case ERF_TYPE_MC_AAL5:
+ case ERF_TYPE_MC_AAL2:
+ case ERF_TYPE_COLOR_MC_HDLC_POS:
+ hdrsize += sizeof(struct erf_mc_hdr);
+ break;
+ case ERF_TYPE_ETH:
+ case ERF_TYPE_COLOR_ETH:
+ case ERF_TYPE_DSM_COLOR_ETH:
+ hdrsize += sizeof(struct erf_eth_hdr);
+ break;
+ default:
+ break;
+ }
+ break;
+
default:
hdrsize = 0;
break;
@@ -2508,6 +2757,50 @@ static gboolean libpcap_dump(wtap_dumper *wdh,
}
wdh->bytes_dumped += sizeof(lapd_hdr);
break;
+
+ case WTAP_ENCAP_ERF:
+ /*
+ * Write the ERF header.
+ */
+ memset(&erf_hdr, 0, sizeof(erf_hdr));
+ pletonll(&erf_hdr[0], pseudo_header->erf.phdr.ts);
+ erf_hdr[8] = pseudo_header->erf.phdr.type;
+ erf_hdr[9] = pseudo_header->erf.phdr.flags;
+ phtons(&erf_hdr[10], pseudo_header->erf.phdr.rlen);
+ phtons(&erf_hdr[12], pseudo_header->erf.phdr.lctr);
+ phtons(&erf_hdr[14], pseudo_header->erf.phdr.wlen);
+ size = sizeof(struct erf_phdr);
+
+ switch(pseudo_header->erf.phdr.type) {
+ case ERF_TYPE_MC_HDLC:
+ case ERF_TYPE_MC_RAW:
+ case ERF_TYPE_MC_ATM:
+ case ERF_TYPE_MC_RAW_CHANNEL:
+ case ERF_TYPE_MC_AAL5:
+ case ERF_TYPE_MC_AAL2:
+ case ERF_TYPE_COLOR_MC_HDLC_POS:
+ phtonl(&erf_hdr[16], pseudo_header->erf.subhdr.mc_hdr);
+ size += sizeof(struct erf_mc_hdr);
+ break;
+ case ERF_TYPE_ETH:
+ case ERF_TYPE_COLOR_ETH:
+ case ERF_TYPE_DSM_COLOR_ETH:
+ phtons(&erf_hdr[16], pseudo_header->erf.subhdr.eth_hdr);
+ size += sizeof(struct erf_eth_hdr);
+ break;
+ default:
+ break;
+ }
+ nwritten = wtap_dump_file_write(wdh, erf_hdr, size);
+ if (nwritten != (guint) size) {
+ if (nwritten == 0 && wtap_dump_file_ferror(wdh))
+ *err = wtap_dump_file_ferror(wdh);
+ else
+ *err = WTAP_ERR_SHORT_WRITE;
+ return FALSE;
+ }
+ wdh->bytes_dumped += size;
+ break;
}
nwritten = wtap_dump_file_write(wdh, pd, phdr->caplen);