/* * Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand. * All rights reserved. * * This software and documentation has been developed by Endace Technology Ltd. * along with the DAG PCI network capture cards. For further information please * visit http://www.endace.com/. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The name of Endace Technology Ltd may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * 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. */ /* * erf - Endace ERF (Extensible Record Format) * * See * * http://www.endace.com/support/EndaceRecordFormat.pdf * (mirror: https://bugs.wireshark.org/bugzilla/attachment.cgi?id=4333) (bug #4484) */ #include "config.h" #include #include #include #include #include "wtap-int.h" #include "file_wrappers.h" #include "pcap-encap.h" #include "pcapng.h" #include "erf.h" 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); static gboolean erf_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info); static const struct { int erf_encap_value; int wtap_encap_value; } erf_to_wtap_map[] = { { ERF_TYPE_HDLC_POS, WTAP_ENCAP_CHDLC }, { ERF_TYPE_HDLC_POS, WTAP_ENCAP_HHDLC }, { ERF_TYPE_HDLC_POS, WTAP_ENCAP_CHDLC_WITH_PHDR }, { ERF_TYPE_HDLC_POS, WTAP_ENCAP_PPP }, { ERF_TYPE_HDLC_POS, WTAP_ENCAP_FRELAY }, { ERF_TYPE_HDLC_POS, WTAP_ENCAP_MTP2 }, { ERF_TYPE_ETH, WTAP_ENCAP_ETHERNET }, { 99, WTAP_ENCAP_ERF }, /*this type added so WTAP_ENCAP_ERF will work and then be treated at ERF->ERF*/ }; #define NUM_ERF_ENCAPS (sizeof erf_to_wtap_map / sizeof erf_to_wtap_map[0]) 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; struct erf_eth_hdr eth_hdr; guint32 packet_size; guint16 rlen; guint64 erf_ext_header; guint8 type; gboolean r; gchar * buffer; memset(&prevts, 0, sizeof(prevts)); /* number of records to scan before deciding if this really is ERF */ if ((s = getenv("ERF_RECORDS_TO_CHECK")) != NULL) { if ((n = atoi(s)) > 0 && n < 101) { records_for_erf_check = n; } } /* * ERF is a little hard because there's no magic number; we look at * the first few records and see if they look enough like ERF * records. */ for (i = 0; i < records_for_erf_check; i++) { /* records_for_erf_check */ 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 { 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 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. */ 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 WTAP_OPEN_ERROR; } continue; } /* 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 WTAP_OPEN_NOT_MINE; } 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 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 WTAP_OPEN_NOT_MINE; } memcpy(&prevts, &ts, sizeof(prevts)); /* Read over the extension headers */ type = header.type; while (type & 0x80){ 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 (!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 or a file that's not an ERF file * but that passed earlier tests. */ return WTAP_OPEN_NOT_MINE; } buffer=(gchar *)g_malloc(packet_size); r = wtap_read_bytes(wth->fh, buffer, packet_size, err, err_info); g_free(buffer); 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 */ if (i < MIN_RECORDS_FOR_ERF_CHECK) { return WTAP_OPEN_NOT_MINE; } } valid_prev = 1; } /* records_for_erf_check */ if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) { /* rewind */ return WTAP_OPEN_ERROR; } /* This is an ERF file */ 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. */ wth->file_encap = WTAP_ENCAP_ERF; wth->subtype_read = erf_read; wth->subtype_seek_read = erf_seek_read; wth->file_tsprec = WTAP_TSPREC_NSEC; erf_populate_interfaces(wth); return WTAP_OPEN_MINE; } /* Read the next packet */ static gboolean erf_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset) { erf_header_t erf_header; guint32 packet_size, bytes_read; *data_offset = file_tell(wth->fh); do { if (!erf_read_header(wth->fh, &wth->phdr, &erf_header, err, err_info, &bytes_read, &packet_size)) { return FALSE; } if (!wtap_read_packet_bytes(wth->fh, wth->frame_buffer, packet_size, err, err_info)) return FALSE; } while ( erf_header.type == ERF_TYPE_PAD ); return TRUE; } static gboolean erf_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info) { erf_header_t erf_header; 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, phdr, &erf_header, err, err_info, NULL, &packet_size)) return FALSE; } while ( erf_header.type == ERF_TYPE_PAD ); return wtap_read_packet_bytes(wth->random_fh, buf, packet_size, err, err_info); } 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; guint8 erf_exhdr[8]; guint64 erf_exhdr_sw; guint8 type = 0; guint32 mc_hdr; guint32 aal2_hdr; struct wtap_erf_eth_hdr eth_hdr; guint32 skiplen = 0; int i = 0; int max = sizeof(pseudo_header->erf.ehdr_list)/sizeof(struct erf_ehdr); 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); } *packet_size = g_ntohs(erf_header->rlen) - (guint32)sizeof(*erf_header); 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. */ *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; } if (*packet_size == 0) { /* 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; } } { 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 & 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 = 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); pseudo_header->erf.phdr.lctr = g_ntohs(erf_header->lctr); pseudo_header->erf.phdr.wlen = g_ntohs(erf_header->wlen); /* Copy the ERF extension header into the pseudo header */ type = erf_header->type; while (type & 0x80){ 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: 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 = 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: 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_ntohl(mc_hdr); break; case ERF_TYPE_AAL2: if (!wtap_read_bytes(fh, &aal2_hdr, sizeof(aal2_hdr), err, err_info)) return FALSE; if (bytes_read != NULL) *bytes_read += (guint32)sizeof(aal2_hdr); *packet_size -= (guint32)sizeof(aal2_hdr); skiplen += (guint32)sizeof(aal2_hdr); pseudo_header->erf.subhdr.aal2_hdr = g_ntohl(aal2_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; } { phdr->len = g_ntohs(erf_header->wlen); phdr->caplen = MIN( g_ntohs(erf_header->wlen), g_ntohs(erf_header->rlen) - (guint32)sizeof(*erf_header) - skiplen ); } 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. */ *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; } return TRUE; } static int wtap_wtap_encap_to_erf_encap(int encap) { unsigned int i; for(i = 0; i < NUM_ERF_ENCAPS; i++){ if(erf_to_wtap_map[i].wtap_encap_value == encap) return erf_to_wtap_map[i].erf_encap_value; } return -1; } static gboolean erf_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pseudo_header, int * err) { guint8 erf_hdr[sizeof(struct erf_mc_phdr)]; guint8 erf_subhdr[sizeof(union erf_subhdr)]; guint8 ehdr[8*MAX_ERF_EHDR]; size_t size = 0; size_t subhdr_size = 0; int i = 0; guint8 has_more = 0; switch(encap){ case WTAP_ENCAP_ERF: memset(&erf_hdr, 0, sizeof(erf_hdr)); 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); 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 & 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: phtonl(&erf_subhdr[0], pseudo_header->erf.subhdr.mc_hdr); subhdr_size += (int)sizeof(struct erf_mc_hdr); break; case ERF_TYPE_AAL2: phtonl(&erf_subhdr[0], pseudo_header->erf.subhdr.aal2_hdr); subhdr_size += (int)sizeof(struct erf_aal2_hdr); break; case ERF_TYPE_ETH: case ERF_TYPE_COLOR_ETH: case ERF_TYPE_DSM_COLOR_ETH: case ERF_TYPE_COLOR_HASH_ETH: memcpy(&erf_subhdr[0], &pseudo_header->erf.subhdr.eth_hdr, sizeof pseudo_header->erf.subhdr.eth_hdr); subhdr_size += (int)sizeof(struct erf_eth_hdr); break; default: break; } break; default: return FALSE; } if (!wtap_dump_file_write(wdh, erf_hdr, size, err)) return FALSE; wdh->bytes_dumped += size; /*write out up to MAX_ERF_EHDR 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(has_more && i < MAX_ERF_EHDR); if (!wtap_dump_file_write(wdh, ehdr, 8*i, err)) return FALSE; wdh->bytes_dumped += 8*i; } if(!wtap_dump_file_write(wdh, erf_subhdr, subhdr_size, err)) return FALSE; wdh->bytes_dumped += subhdr_size; return TRUE; } static gboolean erf_dump( 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; gboolean must_add_crc = FALSE; 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; }else{ encap = wdh->encap; } 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(!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; } /*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 - (guint)alignbytes) % 8; other_phdr.erf.phdr.rlen -= round_down; }else{ other_phdr.erf.phdr.rlen += (gint16)alignbytes; } 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; /*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; } int erf_dump_can_write_encap(int encap) { if(encap == WTAP_ENCAP_PER_PACKET) return 0; if (wtap_wtap_encap_to_erf_encap(encap) == -1) return WTAP_ERR_UNWRITABLE_ENCAP; return 0; } int erf_dump_open(wtap_dumper *wdh, int *err) { wdh->subtype_write = erf_dump; switch(wdh->file_type_subtype){ case WTAP_FILE_TYPE_SUBTYPE_ERF: wdh->tsprecision = WTAP_TSPREC_NSEC; break; default: *err = WTAP_ERR_UNWRITABLE_FILE_TYPE; return FALSE; break; } return TRUE; } int erf_populate_interfaces(wtap *wth) { wtap_optionblock_t int_data; wtapng_if_descr_mandatory_t* int_data_mand; int i; char* tmp; if (!wth) return -1; /* Preemptively create interface entries for 4 interfaces, since this is the max number in ERF */ for (i=0; i<4; i++) { int_data = wtap_optionblock_create(WTAP_OPTION_BLOCK_IF_DESCR); int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(int_data); int_data_mand->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_mand->time_units_per_second = 1000000000; /* XXX Since Wireshark only supports down to nanosecond resolution we have to dilute to this */ int_data_mand->link_type = wtap_wtap_encap_to_pcap_encap(WTAP_ENCAP_ERF); int_data_mand->snap_len = 65535; /* ERF max length */ /* 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)*/ wtap_optionblock_set_option_uint64(int_data, OPT_IDB_SPEED, 0); /* Unknown - XXX should be left at default? */ /* int_data.if_tsresol = 0xa0; ERF format resolution is 2^-32 = 0xa0, capture resolution is unknown */ wtap_optionblock_set_option_uint8(int_data, OPT_IDB_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). */ /* XXX if_tsoffset; opt 14 A 64 bits integer value that specifies an offset (in seconds)...*/ /* Interface statistics */ int_data_mand->num_stat_entries = 0; int_data_mand->interface_statistics = NULL; tmp = g_strdup_printf("Port %c", 'A'+i); wtap_optionblock_set_option_string(int_data, OPT_IDB_NAME, tmp); g_free(tmp); tmp = g_strdup_printf("ERF Interface Id %d (Port %c)", i, 'A'+i); wtap_optionblock_set_option_string(int_data, OPT_IDB_DESCR, tmp); g_free(tmp); 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: */