X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=wiretap%2Ferf.c;h=088845bd6b468e4fe1fe9ee9a41c23450e8b4093;hb=ffa9e938e24779470c664ea8eca1e452ce025f97;hp=a3be2e2555dae9cfa8b5cda205657ad22ff3fb25;hpb=666b58d40876dbcb247f25cc180c312d2bb8a9d2;p=metze%2Fwireshark%2Fwip.git diff --git a/wiretap/erf.c b/wiretap/erf.c index a3be2e2555..088845bd6b 100644 --- a/wiretap/erf.c +++ b/wiretap/erf.c @@ -30,8 +30,6 @@ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. - * - * $Id$ */ /* @@ -39,37 +37,36 @@ * * See * - * http://www.endace.com/support/EndaceRecordFormat.pdf + * http://www.endace.com/support/EndaceRecordFormat.pdf + * (mirror: https://bugs.wireshark.org/bugzilla/attachment.cgi?id=4333) (bug #4484) */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #include #include -#include +#include + +#include #include "wtap-int.h" #include "file_wrappers.h" -#include "buffer.h" -#include "atm.h" +#include "pcap-encap.h" #include "erf.h" -static int erf_read_header(FILE_T fh, - struct wtap_pkthdr *phdr, - union wtap_pseudo_header *pseudo_header, - erf_header_t *erf_header, - int *err, - gchar **err_info, - guint32 *bytes_read, - guint32 *packet_size); +static gboolean erf_read_header(FILE_T fh, + struct wtap_pkthdr *phdr, + erf_header_t *erf_header, + int *err, + gchar **err_info, + guint32 *bytes_read, + guint32 *packet_size); static gboolean erf_read(wtap *wth, int *err, gchar **err_info, - gint64 *data_offset); + gint64 *data_offset); static gboolean erf_seek_read(wtap *wth, gint64 seek_off, - union wtap_pseudo_header *pseudo_header, guint8 *pd, - int length, int *err, gchar **err_info); + struct wtap_pkthdr *phdr, Buffer *buf, + int *err, gchar **err_info); static const struct { int erf_encap_value; @@ -87,21 +84,21 @@ static const struct { #define NUM_ERF_ENCAPS (sizeof erf_to_wtap_map / sizeof erf_to_wtap_map[0]) -extern int erf_open(wtap *wth, int *err, gchar **err_info) +extern wtap_open_return_val erf_open(wtap *wth, int *err, gchar **err_info) { - int i, n, records_for_erf_check = RECORDS_FOR_ERF_CHECK; - int valid_prev = 0; - char *s; - erf_timestamp_t prevts,ts; - erf_header_t header; - guint32 mc_hdr; - guint16 eth_hdr; - guint32 packet_size; - guint16 rlen; - guint64 erf_ext_header; - guint8 type; - size_t r; - gchar * buffer; + int i, n, records_for_erf_check = RECORDS_FOR_ERF_CHECK; + int valid_prev = 0; + char *s; + erf_timestamp_t prevts,ts; + erf_header_t header; + guint32 mc_hdr; + guint16 eth_hdr; + guint32 packet_size; + guint16 rlen; + guint64 erf_ext_header; + guint8 type; + gboolean r; + gchar * buffer; memset(&prevts, 0, sizeof(prevts)); @@ -120,47 +117,47 @@ extern int erf_open(wtap *wth, int *err, gchar **err_info) for (i = 0; i < records_for_erf_check; i++) { /* records_for_erf_check */ - r = file_read(&header,sizeof(header),wth->fh); - - if (r == 0 ) break; - if (r != sizeof(header)) { - if ((*err = file_error(wth->fh, err_info)) != 0) { - return -1; + if (!wtap_read_bytes_or_eof(wth->fh,&header,sizeof(header),err,err_info)) { + if (*err == 0) { + /* EOF - all records have been successfully checked, accept the file */ + break; + } + if (*err == WTAP_ERR_SHORT_READ) { + /* ERF header too short accept the file, + only if the very first records have been successfully checked */ + if (i < MIN_RECORDS_FOR_ERF_CHECK) { + return WTAP_OPEN_NOT_MINE; + } else { + /* BREAK, the last record is too short, and will be ignored */ + break; + } } else { - /* ERF header too short accept the file, - only if the very first records have been successfully checked */ - if (i < MIN_RECORDS_FOR_ERF_CHECK) { - return 0; - } else { - /* BREAK, the last record is too short, and will be ignored */ - break; - } + return WTAP_OPEN_ERROR; } } rlen=g_ntohs(header.rlen); /* fail on invalid record type, invalid rlen, timestamps decreasing, or incrementing too far */ - + /* Test valid rlen >= 16 */ if (rlen < 16) { - return 0; + return WTAP_OPEN_NOT_MINE; } - + packet_size = rlen - (guint32)sizeof(header); if (packet_size > WTAP_MAX_PACKET_SIZE) { /* * Probably a corrupt capture file or a file that's not an ERF file - * but that passed earlier tests; don't blow up trying - * to allocate space for an immensely-large packet. + * but that passed earlier tests. */ - return 0; + return WTAP_OPEN_NOT_MINE; } /* Skip PAD records, timestamps may not be set */ if ((header.type & 0x7F) == ERF_TYPE_PAD) { if (file_seek(wth->fh, packet_size, SEEK_CUR, err) == -1) { - return -1; + return WTAP_OPEN_ERROR; } continue; } @@ -168,87 +165,96 @@ extern int erf_open(wtap *wth, int *err, gchar **err_info) /* fail on invalid record type, decreasing timestamps or non-zero pad-bits */ /* Not all types within this range are decoded, but it is a first filter */ if ((header.type & 0x7F) == 0 || (header.type & 0x7F) > ERF_TYPE_MAX ) { - return 0; + return WTAP_OPEN_NOT_MINE; } - - /* The ERF_TYPE_MAX is the PAD record, but the last used type is ERF_TYPE_INFINIBAND_LINK */ - if ((header.type & 0x7F) > ERF_TYPE_INFINIBAND_LINK) { - return 0; - } - - if ((ts = pletohll(&header.ts)) < prevts) { + + if ((ts = pletoh64(&header.ts)) < prevts) { /* reassembled AALx records may not be in time order, also records are not in strict time order between physical interfaces, so allow 1 sec fudge */ if ( ((prevts-ts)>>32) > 1 ) { - return 0; + return WTAP_OPEN_NOT_MINE; } } - + /* Check to see if timestamp increment is > 1 week */ if ( (valid_prev) && (ts > prevts) && (((ts-prevts)>>32) > 3600*24*7) ) { - return 0; + return WTAP_OPEN_NOT_MINE; } - + memcpy(&prevts, &ts, sizeof(prevts)); /* Read over the extension headers */ type = header.type; while (type & 0x80){ - if (file_read(&erf_ext_header, sizeof(erf_ext_header),wth->fh) != sizeof(erf_ext_header)) { - *err = file_error(wth->fh, err_info); - return -1; - } - packet_size -= (guint32)sizeof(erf_ext_header); - memcpy(&type, &erf_ext_header, sizeof(type)); + if (!wtap_read_bytes(wth->fh,&erf_ext_header,sizeof(erf_ext_header),err,err_info)) { + if (*err == WTAP_ERR_SHORT_READ) { + /* Extension header missing, not an ERF file */ + return WTAP_OPEN_NOT_MINE; + } + return WTAP_OPEN_ERROR; + } + packet_size -= (guint32)sizeof(erf_ext_header); + memcpy(&type, &erf_ext_header, sizeof(type)); } - + /* Read over MC or ETH subheader */ switch(header.type & 0x7F) { - 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: - case ERF_TYPE_AAL2: /* not an MC type but has a similar 'AAL2 ext' header */ - if (file_read(&mc_hdr,sizeof(mc_hdr),wth->fh) != sizeof(mc_hdr)) { - *err = file_error(wth->fh, err_info); - return -1; - } - packet_size -= (guint32)sizeof(mc_hdr); - break; - case ERF_TYPE_ETH: - case ERF_TYPE_COLOR_ETH: - case ERF_TYPE_DSM_COLOR_ETH: - if (file_read(ð_hdr,sizeof(eth_hdr),wth->fh) != sizeof(eth_hdr)) { - *err = file_error(wth->fh, err_info); - return -1; - } - packet_size -= (guint32)sizeof(eth_hdr); - break; - default: - break; + 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: + case ERF_TYPE_AAL2: /* not an MC type but has a similar 'AAL2 ext' header */ + if (!wtap_read_bytes(wth->fh,&mc_hdr,sizeof(mc_hdr),err,err_info)) { + if (*err == WTAP_ERR_SHORT_READ) { + /* Subheader missing, not an ERF file */ + return WTAP_OPEN_NOT_MINE; + } + return WTAP_OPEN_ERROR; + } + packet_size -= (guint32)sizeof(mc_hdr); + break; + case ERF_TYPE_ETH: + case ERF_TYPE_COLOR_ETH: + case ERF_TYPE_DSM_COLOR_ETH: + case ERF_TYPE_COLOR_HASH_ETH: + if (!wtap_read_bytes(wth->fh,ð_hdr,sizeof(eth_hdr),err,err_info)) { + if (*err == WTAP_ERR_SHORT_READ) { + /* Subheader missing, not an ERF file */ + return WTAP_OPEN_NOT_MINE; + } + return WTAP_OPEN_ERROR; + } + packet_size -= (guint32)sizeof(eth_hdr); + break; + default: + break; } /* The file_seek function do not return an error if the end of file is reached whereas the record is truncated */ if (packet_size > WTAP_MAX_PACKET_SIZE) { /* - * Probably a corrupt capture file; don't blow up trying - * to allocate space for an immensely-large packet. + * Probably a corrupt capture file or a file that's not an ERF file + * but that passed earlier tests. */ - return 0; + return WTAP_OPEN_NOT_MINE; } - buffer=g_malloc(packet_size); - r = file_read(buffer, packet_size, wth->fh); + buffer=(gchar *)g_malloc(packet_size); + r = wtap_read_bytes(wth->fh, buffer, packet_size, err, err_info); g_free(buffer); - if (r != packet_size) { + if (!r) { + if (*err != WTAP_ERR_SHORT_READ) { + /* A real error */ + return WTAP_OPEN_ERROR; + } /* ERF record too short, accept the file, - only if the very first records have been successfully checked */ + only if the very first records have been successfully checked */ if (i < MIN_RECORDS_FOR_ERF_CHECK) { - return 0; + return WTAP_OPEN_NOT_MINE; } } @@ -256,15 +262,13 @@ extern int erf_open(wtap *wth, int *err, gchar **err_info) } /* records_for_erf_check */ - if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) { /* rewind */ - return -1; + if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) { /* rewind */ + return WTAP_OPEN_ERROR; } - wth->data_offset = 0; - /* This is an ERF file */ - wth->file_type = WTAP_FILE_ERF; - wth->snapshot_length = 0; /* not available in header, only in frame */ + wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ERF; + wth->snapshot_length = 0; /* not available in header, only in frame */ /* * Use the encapsulation for ERF records. @@ -273,33 +277,32 @@ extern int erf_open(wtap *wth, int *err, gchar **err_info) wth->subtype_read = erf_read; wth->subtype_seek_read = erf_seek_read; - wth->tsprecision = WTAP_FILE_TSPREC_NSEC; + wth->file_tsprec = WTAP_TSPREC_NSEC; + + erf_populate_interfaces(wth); - return 1; + return WTAP_OPEN_MINE; } /* Read the next packet */ static gboolean erf_read(wtap *wth, int *err, gchar **err_info, - gint64 *data_offset) + gint64 *data_offset) { erf_header_t erf_header; - guint32 packet_size, bytes_read; + guint32 packet_size, bytes_read; - *data_offset = wth->data_offset; + *data_offset = file_tell(wth->fh); do { if (!erf_read_header(wth->fh, - &wth->phdr, &wth->pseudo_header, &erf_header, - err, err_info, &bytes_read, &packet_size)) { + &wth->phdr, &erf_header, + err, err_info, &bytes_read, &packet_size)) { return FALSE; } - wth->data_offset += bytes_read; - buffer_assure_space(wth->frame_buffer, packet_size); - - wtap_file_read_expected_bytes(buffer_start_ptr(wth->frame_buffer), - (gint32)(packet_size), wth->fh, err, err_info); - wth->data_offset += packet_size; + if (!wtap_read_packet_bytes(wth->fh, wth->frame_buffer, packet_size, + err, err_info)) + return FALSE; } while ( erf_header.type == ERF_TYPE_PAD ); @@ -307,46 +310,46 @@ static gboolean erf_read(wtap *wth, int *err, gchar **err_info, } static gboolean erf_seek_read(wtap *wth, gint64 seek_off, - union wtap_pseudo_header *pseudo_header, guint8 *pd, - int length _U_, int *err, gchar **err_info) + struct wtap_pkthdr *phdr, Buffer *buf, + int *err, gchar **err_info) { erf_header_t erf_header; - guint32 packet_size; + guint32 packet_size; if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) return FALSE; do { - if (!erf_read_header(wth->random_fh, NULL, pseudo_header, &erf_header, - err, err_info, NULL, &packet_size)) + if (!erf_read_header(wth->random_fh, phdr, &erf_header, + err, err_info, NULL, &packet_size)) return FALSE; } while ( erf_header.type == ERF_TYPE_PAD ); - wtap_file_read_expected_bytes(pd, (int)packet_size, wth->random_fh, err, - err_info); - - return TRUE; + return wtap_read_packet_bytes(wth->random_fh, buf, packet_size, + err, err_info); } -static int erf_read_header(FILE_T fh, - struct wtap_pkthdr *phdr, - union wtap_pseudo_header *pseudo_header, - erf_header_t *erf_header, - int *err, - gchar **err_info, - guint32 *bytes_read, - guint32 *packet_size) +static gboolean erf_read_header(FILE_T fh, + struct wtap_pkthdr *phdr, + erf_header_t *erf_header, + int *err, + gchar **err_info, + guint32 *bytes_read, + guint32 *packet_size) { + union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header; guint32 mc_hdr; - guint8 erf_exhdr[8]; + guint8 erf_exhdr[8]; guint64 erf_exhdr_sw; - guint8 type = 0; + guint8 type = 0; guint16 eth_hdr; - guint32 skiplen=0; - int i = 0 , max = sizeof(pseudo_header->erf.ehdr_list)/sizeof(struct erf_ehdr); + guint32 skiplen = 0; + int i = 0; + int max = sizeof(pseudo_header->erf.ehdr_list)/sizeof(struct erf_ehdr); - wtap_file_read_expected_bytes(erf_header, sizeof(*erf_header), fh, err, - err_info); + if (!wtap_read_bytes_or_eof(fh, erf_header, sizeof(*erf_header), err, err_info)) { + return FALSE; + } if (bytes_read != NULL) { *bytes_read = sizeof(*erf_header); } @@ -358,36 +361,41 @@ static int erf_read_header(FILE_T fh, * Probably a corrupt capture file; don't blow up trying * to allocate space for an immensely-large packet. */ - *err = WTAP_ERR_BAD_RECORD; + *err = WTAP_ERR_BAD_FILE; *err_info = g_strdup_printf("erf: File has %u-byte packet, bigger than maximum of %u", - *packet_size, WTAP_MAX_PACKET_SIZE); + *packet_size, WTAP_MAX_PACKET_SIZE); return FALSE; } if (*packet_size == 0) { - /* Again a corrupt packet, bail out */ - *err = WTAP_ERR_BAD_RECORD; - *err_info = g_strdup_printf("erf: File has 0 byte packet"); + /* If this isn't a pad record, it's a corrupt packet; bail out */ + if ((erf_header->type & 0x7F) != ERF_TYPE_PAD) { + *err = WTAP_ERR_BAD_FILE; + *err_info = g_strdup_printf("erf: File has 0 byte packet"); - return FALSE; + return FALSE; + } } - if (phdr != NULL) { - guint64 ts = pletohll(&erf_header->ts); + { + guint64 ts = pletoh64(&erf_header->ts); + phdr->rec_type = REC_TYPE_PACKET; + phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN|WTAP_HAS_INTERFACE_ID; phdr->ts.secs = (long) (ts >> 32); - ts = ((ts & 0xffffffff) * 1000 * 1000 * 1000); + ts = ((ts & 0xffffffff) * 1000 * 1000 * 1000); ts += (ts & 0x80000000) << 1; /* rounding */ phdr->ts.nsecs = ((int) (ts >> 32)); if (phdr->ts.nsecs >= 1000000000) { phdr->ts.nsecs -= 1000000000; phdr->ts.secs += 1; } + phdr->interface_id = (erf_header->flags & 0x03); } /* Copy the ERF pseudo header */ memset(&pseudo_header->erf, 0, sizeof(pseudo_header->erf)); - pseudo_header->erf.phdr.ts = pletohll(&erf_header->ts); + pseudo_header->erf.phdr.ts = pletoh64(&erf_header->ts); pseudo_header->erf.phdr.type = erf_header->type; pseudo_header->erf.phdr.flags = erf_header->flags; pseudo_header->erf.phdr.rlen = g_ntohs(erf_header->rlen); @@ -397,84 +405,88 @@ static int erf_read_header(FILE_T fh, /* Copy the ERF extension header into the pseudo header */ type = erf_header->type; while (type & 0x80){ - wtap_file_read_expected_bytes(&erf_exhdr, sizeof(erf_exhdr), fh, err, - err_info); - if (bytes_read != NULL) - *bytes_read += (guint32)sizeof(erf_exhdr); - *packet_size -= (guint32)sizeof(erf_exhdr); - skiplen += (guint32)sizeof(erf_exhdr); - erf_exhdr_sw = pntohll(erf_exhdr); - if (i < max) - memcpy(&pseudo_header->erf.ehdr_list[i].ehdr, &erf_exhdr_sw, sizeof(erf_exhdr_sw)); - type = erf_exhdr[0]; - i++; + if (!wtap_read_bytes(fh, &erf_exhdr, sizeof(erf_exhdr), + err, err_info)) + return FALSE; + if (bytes_read != NULL) + *bytes_read += (guint32)sizeof(erf_exhdr); + *packet_size -= (guint32)sizeof(erf_exhdr); + skiplen += (guint32)sizeof(erf_exhdr); + erf_exhdr_sw = pntoh64(erf_exhdr); + if (i < max) + memcpy(&pseudo_header->erf.ehdr_list[i].ehdr, &erf_exhdr_sw, sizeof(erf_exhdr_sw)); + type = erf_exhdr[0]; + i++; } switch (erf_header->type & 0x7F) { - case ERF_TYPE_IPV4: - case ERF_TYPE_IPV6: - case ERF_TYPE_RAW_LINK: - case ERF_TYPE_INFINIBAND: - case ERF_TYPE_INFINIBAND_LINK: - /*** - if (phdr != NULL) { - phdr->len = g_htons(erf_header->wlen); - phdr->caplen = g_htons(erf_header->wlen); - } - return TRUE; - ***/ - break; - case ERF_TYPE_PAD: - case ERF_TYPE_HDLC_POS: - case ERF_TYPE_COLOR_HDLC_POS: - case ERF_TYPE_DSM_COLOR_HDLC_POS: - case ERF_TYPE_ATM: - case ERF_TYPE_AAL5: - break; - - case ERF_TYPE_ETH: - case ERF_TYPE_COLOR_ETH: - case ERF_TYPE_DSM_COLOR_ETH: - wtap_file_read_expected_bytes(ð_hdr, sizeof(eth_hdr), fh, err, - err_info); - if (bytes_read != NULL) - *bytes_read += (guint32)sizeof(eth_hdr); - *packet_size -= (guint32)sizeof(eth_hdr); - skiplen += (guint32)sizeof(eth_hdr); - pseudo_header->erf.subhdr.eth_hdr = g_htons(eth_hdr); - break; - - 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: - case ERF_TYPE_AAL2: /* not an MC type but has a similar 'AAL2 ext' header */ - wtap_file_read_expected_bytes(&mc_hdr, sizeof(mc_hdr), fh, err, - err_info); - if (bytes_read != NULL) - *bytes_read += (guint32)sizeof(mc_hdr); - *packet_size -= (guint32)sizeof(mc_hdr); - skiplen += (guint32)sizeof(mc_hdr); - pseudo_header->erf.subhdr.mc_hdr = g_htonl(mc_hdr); - break; - - case ERF_TYPE_IP_COUNTER: - case ERF_TYPE_TCP_FLOW_COUNTER: - /* unsupported, continue with default: */ - default: - *err = WTAP_ERR_UNSUPPORTED_ENCAP; - *err_info = g_strdup_printf("erf: unknown record encapsulation %u", - erf_header->type); - return FALSE; + case ERF_TYPE_IPV4: + case ERF_TYPE_IPV6: + case ERF_TYPE_RAW_LINK: + case ERF_TYPE_INFINIBAND: + case ERF_TYPE_INFINIBAND_LINK: + case ERF_TYPE_META: +#if 0 + { + phdr->len = g_htons(erf_header->wlen); + phdr->caplen = g_htons(erf_header->wlen); + } + return TRUE; +#endif + break; + case ERF_TYPE_PAD: + case ERF_TYPE_HDLC_POS: + case ERF_TYPE_COLOR_HDLC_POS: + case ERF_TYPE_DSM_COLOR_HDLC_POS: + case ERF_TYPE_COLOR_HASH_POS: + case ERF_TYPE_ATM: + case ERF_TYPE_AAL5: + break; + + case ERF_TYPE_ETH: + case ERF_TYPE_COLOR_ETH: + case ERF_TYPE_DSM_COLOR_ETH: + case ERF_TYPE_COLOR_HASH_ETH: + if (!wtap_read_bytes(fh, ð_hdr, sizeof(eth_hdr), err, err_info)) + return FALSE; + if (bytes_read != NULL) + *bytes_read += (guint32)sizeof(eth_hdr); + *packet_size -= (guint32)sizeof(eth_hdr); + skiplen += (guint32)sizeof(eth_hdr); + pseudo_header->erf.subhdr.eth_hdr = g_htons(eth_hdr); + break; + + 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: + case ERF_TYPE_AAL2: /* not an MC type but has a similar 'AAL2 ext' header */ + if (!wtap_read_bytes(fh, &mc_hdr, sizeof(mc_hdr), err, err_info)) + return FALSE; + if (bytes_read != NULL) + *bytes_read += (guint32)sizeof(mc_hdr); + *packet_size -= (guint32)sizeof(mc_hdr); + skiplen += (guint32)sizeof(mc_hdr); + pseudo_header->erf.subhdr.mc_hdr = g_htonl(mc_hdr); + break; + + case ERF_TYPE_IP_COUNTER: + case ERF_TYPE_TCP_FLOW_COUNTER: + /* unsupported, continue with default: */ + default: + *err = WTAP_ERR_UNSUPPORTED; + *err_info = g_strdup_printf("erf: unknown record encapsulation %u", + erf_header->type); + return FALSE; } - if (phdr != NULL) { + { phdr->len = g_htons(erf_header->wlen); phdr->caplen = MIN( g_htons(erf_header->wlen), - g_htons(erf_header->rlen) - (guint32)sizeof(*erf_header) - skiplen ); + g_htons(erf_header->rlen) - (guint32)sizeof(*erf_header) - skiplen ); } if (*packet_size > WTAP_MAX_PACKET_SIZE) { @@ -482,7 +494,7 @@ static int erf_read_header(FILE_T fh, * Probably a corrupt capture file; don't blow up trying * to allocate space for an immensely-large packet. */ - *err = WTAP_ERR_BAD_RECORD; + *err = WTAP_ERR_BAD_FILE; *err_info = g_strdup_printf("erf: File has %u-byte packet, bigger than maximum of %u", *packet_size, WTAP_MAX_PACKET_SIZE); return FALSE; @@ -507,14 +519,15 @@ static gboolean erf_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pse guint8 erf_subhdr[((sizeof(struct erf_mc_hdr) > sizeof(struct erf_eth_hdr))? sizeof(struct erf_mc_hdr) : sizeof(struct erf_eth_hdr))]; guint8 ehdr[8*MAX_ERF_EHDR]; - size_t size = 0; + size_t size = 0; size_t subhdr_size = 0; - int i = 0; + int i = 0; + guint8 has_more = 0; switch(encap){ case WTAP_ENCAP_ERF: memset(&erf_hdr, 0, sizeof(erf_hdr)); - pletonll(&erf_hdr[0], pseudo_header->erf.phdr.ts); + phtolell(&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); @@ -536,6 +549,7 @@ static gboolean erf_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pse case ERF_TYPE_ETH: case ERF_TYPE_COLOR_ETH: case ERF_TYPE_DSM_COLOR_ETH: + case ERF_TYPE_COLOR_HASH_ETH: phtons(&erf_subhdr[0], pseudo_header->erf.subhdr.eth_hdr); subhdr_size += (int)sizeof(struct erf_eth_hdr); break; @@ -552,15 +566,17 @@ static gboolean erf_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pse wdh->bytes_dumped += size; /*write out up to MAX_ERF_EHDR extension headers*/ - if((pseudo_header->erf.phdr.type & 0x80) != 0){ /*we have extension headers*/ + has_more = pseudo_header->erf.phdr.type & 0x80; + if(has_more){ /*we have extension headers*/ do{ phtonll(ehdr+(i*8), pseudo_header->erf.ehdr_list[i].ehdr); if(i == MAX_ERF_EHDR-1) ehdr[i*8] = ehdr[i*8] & 0x7F; + has_more = ehdr[i*8] & 0x80; i++; - }while((ehdr[0] & 0x80) != 0 && i < MAX_ERF_EHDR); - if (!wtap_dump_file_write(wdh, ehdr, MAX_ERF_EHDR*i, err)) + }while(has_more && i < MAX_ERF_EHDR); + if (!wtap_dump_file_write(wdh, ehdr, 8*i, err)) return FALSE; - wdh->bytes_dumped += MAX_ERF_EHDR*i; + wdh->bytes_dumped += 8*i; } if(!wtap_dump_file_write(wdh, erf_subhdr, subhdr_size, err)) @@ -571,19 +587,32 @@ static gboolean erf_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pse } static gboolean erf_dump( - wtap_dumper *wdh, - const struct wtap_pkthdr *phdr, - const union wtap_pseudo_header *pseudo_header, - const guint8 *pd, - int *err) + wtap_dumper *wdh, + const struct wtap_pkthdr *phdr, + const guint8 *pd, + int *err, + gchar **err_info _U_) { + const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header; union wtap_pseudo_header other_phdr; - int encap; - gint64 alignbytes = 0; - int i; - int round_down = 0; + int encap; + gint64 alignbytes = 0; + int i; + int round_down = 0; gboolean must_add_crc = FALSE; - guint32 crc32 = 0x00000000; + guint32 crc32 = 0x00000000; + + /* We can only write packet records. */ + if (phdr->rec_type != REC_TYPE_PACKET) { + *err = WTAP_ERR_UNWRITABLE_REC_TYPE; + return FALSE; + } + + /* Don't write anything bigger than we're willing to read. */ + if(phdr->caplen > WTAP_MAX_PACKET_SIZE) { + *err = WTAP_ERR_PACKET_TOO_LARGE; + return FALSE; + } if(wdh->encap == WTAP_ENCAP_PER_PACKET){ encap = phdr->pkt_encap; @@ -591,87 +620,88 @@ static gboolean erf_dump( encap = wdh->encap; } - switch(encap){ - case WTAP_ENCAP_ERF: - alignbytes = wdh->bytes_dumped + pseudo_header->erf.phdr.rlen; + if(encap == WTAP_ENCAP_ERF){ + /* We've been handed an ERF record, so there's not much to do here. */ + alignbytes = wdh->bytes_dumped + pseudo_header->erf.phdr.rlen; - if(!erf_write_phdr(wdh, encap, pseudo_header, err)) return FALSE; + if(!erf_write_phdr(wdh, encap, pseudo_header, err)) return FALSE; - if(!wtap_dump_file_write(wdh, pd, phdr->caplen, err)) return FALSE; - wdh->bytes_dumped += phdr->caplen; + if(!wtap_dump_file_write(wdh, pd, phdr->caplen, err)) return FALSE; + wdh->bytes_dumped += phdr->caplen; + + /*XXX: this pads the record to its original length, which is fine in most + * cases. However with >MAX_ERF_EHDR unnecessary padding will be added, and + * if the record was truncated this will be incorrectly treated as payload. + * More than 8 extension headers is unusual though, only the first 8 are + * written out anyway and fixing properly would require major refactor.*/ + while(wdh->bytes_dumped < alignbytes){ + if(!wtap_dump_file_write(wdh, "", 1, err)) return FALSE; + wdh->bytes_dumped++; + } + return TRUE; + } - while(wdh->bytes_dumped < alignbytes){ - if(!wtap_dump_file_write(wdh, "", 1, err)) return FALSE; - wdh->bytes_dumped++; + /*generate a fake header in other_phdr using data that we know*/ + /*covert time erf timestamp format*/ + other_phdr.erf.phdr.ts = ((guint64) phdr->ts.secs << 32) + (((guint64) phdr->ts.nsecs <<32) / 1000 / 1000 / 1000); + other_phdr.erf.phdr.type = wtap_wtap_encap_to_erf_encap(encap); + other_phdr.erf.phdr.flags = 0x4; /*vlen flag set because we're creating variable length records*/ + other_phdr.erf.phdr.lctr = 0; + /*now we work out rlen, accounting for all the different headers and missing fcs(eth)*/ + other_phdr.erf.phdr.rlen = phdr->caplen+16; + other_phdr.erf.phdr.wlen = phdr->len; + switch(other_phdr.erf.phdr.type){ + case ERF_TYPE_ETH: + other_phdr.erf.phdr.rlen += 2; /*2 bytes for erf eth_type*/ + if (pseudo_header->eth.fcs_len != 4) { + /* Either this packet doesn't include the FCS + (pseudo_header->eth.fcs_len = 0), or we don't + know whether it has an FCS (= -1). We have to + synthesize an FCS.*/ + if(!(phdr->caplen < phdr->len)){ /*don't add FCS if packet has been snapped off*/ + crc32 = crc32_ccitt_seed(pd, phdr->caplen, 0xFFFFFFFF); + other_phdr.erf.phdr.rlen += 4; /*4 bytes for added checksum*/ + other_phdr.erf.phdr.wlen += 4; + must_add_crc = TRUE; + } } - must_add_crc = TRUE; /* XXX - not if this came from an ERF file with an FCS! */ break; - default: /*deal with generic wtap format*/ - /*generate a fake header in other_phdr using data that we know*/ - /*covert time erf timestamp format*/ - other_phdr.erf.phdr.ts = ((guint64) phdr->ts.secs << 32) + (((guint64) phdr->ts.nsecs <<32) / 1000 / 1000 / 1000); - other_phdr.erf.phdr.type = wtap_wtap_encap_to_erf_encap(encap); - other_phdr.erf.phdr.flags = 0x4; /*vlen flag set because we're creating variable length records*/ - other_phdr.erf.phdr.lctr = 0; - /*now we work out rlen, accounting for all the different headers and missing fcs(eth)*/ - other_phdr.erf.phdr.rlen = phdr->caplen+16; - other_phdr.erf.phdr.wlen = phdr->len; - switch(other_phdr.erf.phdr.type){ - case ERF_TYPE_ETH: - other_phdr.erf.phdr.rlen += 2; /*2 bytes for erf eth_type*/ - if (pseudo_header->eth.fcs_len != 4) { - /* Either this packet doesn't include the FCS - (pseudo_header->eth.fcs_len = 0), or we don't - know whether it has an FCS (= -1). We have to - synthesize an FCS.*/ - - if(!(phdr->caplen < phdr->len)){ /*don't add FCS if packet has been snapped off*/ - crc32 = crc32_ccitt_seed(pd, phdr->caplen, 0xFFFFFFFF); - other_phdr.erf.phdr.rlen += 4; /*4 bytes for added checksum*/ - other_phdr.erf.phdr.wlen += 4; - must_add_crc = TRUE; - } - } - break; - case ERF_TYPE_HDLC_POS: - /*we assume that it's missing a FCS checksum, make one up*/ - if(!(phdr->caplen < phdr->len)){ /*unless of course, the packet has been snapped off*/ - crc32 = crc32_ccitt_seed(pd, phdr->caplen, 0xFFFFFFFF); - other_phdr.erf.phdr.rlen += 4; /*4 bytes for added checksum*/ - other_phdr.erf.phdr.wlen += 4; - must_add_crc = TRUE; /* XXX - these never have an FCS? */ - } - break; - default: - break; - } - - alignbytes = (8 - (other_phdr.erf.phdr.rlen % 8)) % 8; /*calculate how much padding will be required */ - if(phdr->caplen < phdr->len){ /*if packet has been snapped, we need to round down what we output*/ - round_down = (8 - alignbytes) % 8; - other_phdr.erf.phdr.rlen -= round_down; - }else{ - other_phdr.erf.phdr.rlen += (gint16)alignbytes; + case ERF_TYPE_HDLC_POS: + /*we assume that it's missing a FCS checksum, make one up*/ + if(!(phdr->caplen < phdr->len)){ /*unless of course, the packet has been snapped off*/ + crc32 = crc32_ccitt_seed(pd, phdr->caplen, 0xFFFFFFFF); + other_phdr.erf.phdr.rlen += 4; /*4 bytes for added checksum*/ + other_phdr.erf.phdr.wlen += 4; + must_add_crc = TRUE; /* XXX - these never have an FCS? */ } + break; + default: + break; + } - if(!erf_write_phdr(wdh, WTAP_ENCAP_ERF, &other_phdr, err)) return FALSE; - if(!wtap_dump_file_write(wdh, pd, phdr->caplen - round_down, err)) return FALSE; - wdh->bytes_dumped += phdr->caplen - round_down; + alignbytes = (8 - (other_phdr.erf.phdr.rlen % 8)) % 8; /*calculate how much padding will be required */ + if(phdr->caplen < phdr->len){ /*if packet has been snapped, we need to round down what we output*/ + round_down = (8 - (guint)alignbytes) % 8; + other_phdr.erf.phdr.rlen -= round_down; + }else{ + other_phdr.erf.phdr.rlen += (gint16)alignbytes; + } - /*add the 4 byte CRC if necessary*/ - if(must_add_crc){ - if(!wtap_dump_file_write(wdh, &crc32, 4, err)) return FALSE; - wdh->bytes_dumped += 4; - } - /*records should be 8byte aligned, so we add padding*/ - if(round_down == 0){ - for(i = (gint16)alignbytes; i > 0; i--){ - if(!wtap_dump_file_write(wdh, "", 1, err)) return FALSE; - wdh->bytes_dumped++; - } - } + if(!erf_write_phdr(wdh, WTAP_ENCAP_ERF, &other_phdr, err)) return FALSE; + if(!wtap_dump_file_write(wdh, pd, phdr->caplen - round_down, err)) return FALSE; + wdh->bytes_dumped += phdr->caplen - round_down; - break; + /*add the 4 byte CRC if necessary*/ + if(must_add_crc){ + if(!wtap_dump_file_write(wdh, &crc32, 4, err)) return FALSE; + wdh->bytes_dumped += 4; + } + /*records should be 8byte aligned, so we add padding*/ + if(round_down == 0){ + for(i = (gint16)alignbytes; i > 0; i--){ + if(!wtap_dump_file_write(wdh, "", 1, err)) return FALSE; + wdh->bytes_dumped++; + } } return TRUE; @@ -684,7 +714,7 @@ int erf_dump_can_write_encap(int encap) return 0; if (wtap_wtap_encap_to_erf_encap(encap) == -1) - return WTAP_ERR_UNSUPPORTED_ENCAP; + return WTAP_ERR_UNWRITABLE_ENCAP; return 0; } @@ -692,17 +722,74 @@ int erf_dump_can_write_encap(int encap) int erf_dump_open(wtap_dumper *wdh, int *err) { wdh->subtype_write = erf_dump; - wdh->subtype_close = NULL; - switch(wdh->file_type){ - case WTAP_FILE_ERF: - wdh->tsprecision = WTAP_FILE_TSPREC_NSEC; + switch(wdh->file_type_subtype){ + case WTAP_FILE_TYPE_SUBTYPE_ERF: + wdh->tsprecision = WTAP_TSPREC_NSEC; break; default: - *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE; + *err = WTAP_ERR_UNWRITABLE_FILE_TYPE; return FALSE; break; } return TRUE; } + +int erf_populate_interfaces(wtap *wth) +{ + wtapng_if_descr_t int_data; + int i; + + if (!wth) + return -1; + + memset(&int_data, 0, sizeof(int_data)); /* Zero all fields */ + + int_data.wtap_encap = WTAP_ENCAP_ERF; + /* int_data.time_units_per_second = (1LL<<32); ERF format resolution is 2^-32, capture resolution is unknown */ + int_data.time_units_per_second = 1000000000; /* XXX Since Wireshark only supports down to nanosecond resolution we have to dilute to this */ + int_data.link_type = wtap_wtap_encap_to_pcap_encap(WTAP_ENCAP_ERF); + int_data.snap_len = 65535; /* ERF max length */ + int_data.opt_comment = NULL; + /* XXX: if_IPv4addr opt 4 Interface network address and netmask.*/ + /* XXX: if_IPv6addr opt 5 Interface network address and prefix length (stored in the last byte).*/ + /* XXX: if_MACaddr opt 6 Interface Hardware MAC address (48 bits).*/ + /* XXX: if_EUIaddr opt 7 Interface Hardware EUI address (64 bits)*/ + int_data.if_speed = 0; /* Unknown */ + /* int_data.if_tsresol = 0xa0; ERF format resolution is 2^-32 = 0xa0, capture resolution is unknown */ + int_data.if_tsresol = 0x09; /* XXX Since Wireshark only supports down to nanosecond resolution we have to dilute to this */ + /* XXX: if_tzone 10 Time zone for GMT support (TODO: specify better). */ + int_data.if_filter_str = NULL; + int_data.bpf_filter_len = 0; + int_data.if_filter_bpf_bytes = NULL; + int_data.if_os = NULL; + int_data.if_fcslen = 0; /* unknown! */ + /* XXX if_tsoffset; opt 14 A 64 bits integer value that specifies an offset (in seconds)...*/ + /* Interface statistics */ + int_data.num_stat_entries = 0; + int_data.interface_statistics = NULL; + + /* Preemptively create interface entries for 4 interfaces, since this is the max number in ERF */ + for (i=0; i<4; i++) { + int_data.if_name = g_strdup_printf("Port %c", 'A'+i); + int_data.if_description = g_strdup_printf("ERF Interface Id %d (Port %c)", i, 'A'+i); + + g_array_append_val(wth->interface_data, int_data); + } + + return 0; +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local Variables: + * c-basic-offset: 2 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=2 tabstop=8 expandtab: + * :indentSize=2:tabSize=8:noTabs=true: + */