2 * Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand.
5 * This software and documentation has been developed by Endace Technology Ltd.
6 * along with the DAG PCI network capture cards. For further information please
7 * visit http://www.endace.com/.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. The name of Endace Technology Ltd may not be used to endorse or promote
20 * products derived from this software without specific prior written
23 * THIS SOFTWARE IS PROVIDED BY ENDACE TECHNOLOGY LTD ``AS IS'' AND ANY EXPRESS
24 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
26 * EVENT SHALL ENDACE TECHNOLOGY LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
30 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
36 * erf - Endace ERF (Extensible Record Format)
40 * http://www.endace.com/support/EndaceRecordFormat.pdf
41 * (mirror: https://bugs.wireshark.org/bugzilla/attachment.cgi?id=4333) (bug #4484)
51 #include <wsutil/crc32.h>
54 #include "file_wrappers.h"
55 #include "pcap-encap.h"
59 static gboolean erf_read_header(wtap *wth, FILE_T fh,
60 struct wtap_pkthdr *phdr,
61 erf_header_t *erf_header,
65 guint32 *packet_size);
66 static gboolean erf_read(wtap *wth, int *err, gchar **err_info,
68 static gboolean erf_seek_read(wtap *wth, gint64 seek_off,
69 struct wtap_pkthdr *phdr, Buffer *buf,
70 int *err, gchar **err_info);
71 static void erf_close(wtap *wth);
72 static int populate_summary_info(erf_t *erf_priv, wtap *wth, union wtap_pseudo_header *pseudo_header, guint32 packet_size);
77 } erf_to_wtap_map[] = {
78 { ERF_TYPE_HDLC_POS, WTAP_ENCAP_CHDLC },
79 { ERF_TYPE_HDLC_POS, WTAP_ENCAP_HHDLC },
80 { ERF_TYPE_HDLC_POS, WTAP_ENCAP_CHDLC_WITH_PHDR },
81 { ERF_TYPE_HDLC_POS, WTAP_ENCAP_PPP },
82 { ERF_TYPE_HDLC_POS, WTAP_ENCAP_FRELAY },
83 { ERF_TYPE_HDLC_POS, WTAP_ENCAP_MTP2 },
84 { ERF_TYPE_ETH, WTAP_ENCAP_ETHERNET },
85 { 99, WTAP_ENCAP_ERF }, /*this type added so WTAP_ENCAP_ERF will work and then be treated at ERF->ERF*/
88 #define NUM_ERF_ENCAPS (sizeof erf_to_wtap_map / sizeof erf_to_wtap_map[0])
90 #define ERF_META_TAG_HEADERLEN 4
91 #define ERF_META_TAG_ALIGNED_LENGTH(taglength) ((((guint32)taglength + 0x3U) & ~0x3U) + ERF_META_TAG_HEADERLEN)
105 struct erf_if_mapping {
108 struct erf_if_info interfaces[4];
110 gchar *module_filter_str;
111 gint8 module_fcs_len;
112 guint32 module_snaplen;
113 int interface_metadata;
114 gboolean module_metadata;
117 struct erf_meta_tag {
123 struct erf_meta_read_state {
125 guint32 remaining_len;
127 struct erf_if_mapping *if_map;
131 guint16 parentsectiontype;
132 guint16 parentsectionid;
134 int interface_metadata;
137 static gboolean erf_if_mapping_equal(gconstpointer a, gconstpointer b)
139 const struct erf_if_mapping *if_map_a = (const struct erf_if_mapping*) a;
140 const struct erf_if_mapping *if_map_b = (const struct erf_if_mapping*) b;
142 return if_map_a->source_id == if_map_b->source_id && if_map_a->host_id == if_map_b->host_id;
145 static guint erf_if_mapping_hash(gconstpointer key)
147 const struct erf_if_mapping *if_map = (const struct erf_if_mapping*) key;
149 return (((guint) if_map->host_id) << 16) | if_map->source_id;
152 static void erf_if_mapping_destroy(gpointer key)
155 struct erf_if_mapping *if_map = (struct erf_if_mapping*) key;
157 for (i = 0; i < 4; i++) {
158 g_free(if_map->interfaces[i].name);
159 g_free(if_map->interfaces[i].descr);
162 g_free(if_map->module_filter_str);
166 static struct erf_if_mapping* erf_if_mapping_create(guint64 host_id, guint8 source_id)
169 struct erf_if_mapping *if_map = NULL;
171 if_map = (struct erf_if_mapping*) g_malloc(sizeof(struct erf_if_mapping));
172 memset(if_map, 0, sizeof(struct erf_if_mapping));
174 if_map->host_id = host_id;
175 if_map->source_id = source_id;
177 for (i = 0; i < 4; i++) {
178 if_map->interfaces[i].if_index = -1;
179 if_map->interfaces[i].stream_num = -1;
182 if_map->module_fcs_len = -1;
183 if_map->module_snaplen = (guint32) -1;
184 /* everything else 0 by memset */
189 erf_t *erf_priv_create(void)
193 erf_priv = (erf_t*) g_malloc(sizeof(erf_t));
194 erf_priv->if_map = g_hash_table_new_full(erf_if_mapping_hash, erf_if_mapping_equal, erf_if_mapping_destroy, NULL);
195 erf_priv->implicit_host_id = 0;
196 erf_priv->capture_metadata = FALSE;
197 erf_priv->host_metadata = FALSE;
202 erf_t* erf_priv_free(erf_t* erf_priv)
206 g_hash_table_destroy(erf_priv->if_map);
214 erf_free_data(gpointer data, gpointer user_data _U_)
220 extern wtap_open_return_val erf_open(wtap *wth, int *err, gchar **err_info)
222 int i, n, records_for_erf_check = RECORDS_FOR_ERF_CHECK;
225 erf_timestamp_t prevts,ts;
228 struct erf_eth_hdr eth_hdr;
231 guint64 erf_ext_header;
236 memset(&prevts, 0, sizeof(prevts));
238 /* number of records to scan before deciding if this really is ERF */
239 if ((s = getenv("ERF_RECORDS_TO_CHECK")) != NULL) {
240 if ((n = atoi(s)) > 0 && n < 101) {
241 records_for_erf_check = n;
246 * ERF is a little hard because there's no magic number; we look at
247 * the first few records and see if they look enough like ERF
251 for (i = 0; i < records_for_erf_check; i++) { /* records_for_erf_check */
253 if (!wtap_read_bytes_or_eof(wth->fh,&header,sizeof(header),err,err_info)) {
255 /* EOF - all records have been successfully checked, accept the file */
258 if (*err == WTAP_ERR_SHORT_READ) {
259 /* ERF header too short accept the file,
260 only if the very first records have been successfully checked */
261 if (i < MIN_RECORDS_FOR_ERF_CHECK) {
262 return WTAP_OPEN_NOT_MINE;
264 /* BREAK, the last record is too short, and will be ignored */
268 return WTAP_OPEN_ERROR;
272 rlen=g_ntohs(header.rlen);
274 /* fail on invalid record type, invalid rlen, timestamps decreasing, or incrementing too far */
276 /* Test valid rlen >= 16 */
278 return WTAP_OPEN_NOT_MINE;
281 packet_size = rlen - (guint32)sizeof(header);
282 if (packet_size > WTAP_MAX_PACKET_SIZE) {
284 * Probably a corrupt capture file or a file that's not an ERF file
285 * but that passed earlier tests.
287 return WTAP_OPEN_NOT_MINE;
290 /* Skip PAD records, timestamps may not be set */
291 if ((header.type & 0x7F) == ERF_TYPE_PAD) {
292 if (file_seek(wth->fh, packet_size, SEEK_CUR, err) == -1) {
293 return WTAP_OPEN_ERROR;
298 /* fail on invalid record type, decreasing timestamps or non-zero pad-bits */
299 /* Not all types within this range are decoded, but it is a first filter */
300 if ((header.type & 0x7F) == 0 || (header.type & 0x7F) > ERF_TYPE_MAX ) {
301 return WTAP_OPEN_NOT_MINE;
304 if ((ts = pletoh64(&header.ts)) < prevts) {
305 /* 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 */
306 if ( ((prevts-ts)>>32) > 1 ) {
307 return WTAP_OPEN_NOT_MINE;
311 /* Check to see if timestamp increment is > 1 week */
312 if ( (valid_prev) && (ts > prevts) && (((ts-prevts)>>32) > 3600*24*7) ) {
313 return WTAP_OPEN_NOT_MINE;
316 memcpy(&prevts, &ts, sizeof(prevts));
318 /* Read over the extension headers */
321 if (!wtap_read_bytes(wth->fh,&erf_ext_header,sizeof(erf_ext_header),err,err_info)) {
322 if (*err == WTAP_ERR_SHORT_READ) {
323 /* Extension header missing, not an ERF file */
324 return WTAP_OPEN_NOT_MINE;
326 return WTAP_OPEN_ERROR;
328 packet_size -= (guint32)sizeof(erf_ext_header);
329 memcpy(&type, &erf_ext_header, sizeof(type));
333 /* Read over MC or ETH subheader */
334 switch(header.type & 0x7F) {
335 case ERF_TYPE_MC_HDLC:
336 case ERF_TYPE_MC_RAW:
337 case ERF_TYPE_MC_ATM:
338 case ERF_TYPE_MC_RAW_CHANNEL:
339 case ERF_TYPE_MC_AAL5:
340 case ERF_TYPE_MC_AAL2:
341 case ERF_TYPE_COLOR_MC_HDLC_POS:
342 case ERF_TYPE_AAL2: /* not an MC type but has a similar 'AAL2 ext' header */
343 if (!wtap_read_bytes(wth->fh,&mc_hdr,sizeof(mc_hdr),err,err_info)) {
344 if (*err == WTAP_ERR_SHORT_READ) {
345 /* Subheader missing, not an ERF file */
346 return WTAP_OPEN_NOT_MINE;
348 return WTAP_OPEN_ERROR;
350 packet_size -= (guint32)sizeof(mc_hdr);
353 case ERF_TYPE_COLOR_ETH:
354 case ERF_TYPE_DSM_COLOR_ETH:
355 case ERF_TYPE_COLOR_HASH_ETH:
356 if (!wtap_read_bytes(wth->fh,ð_hdr,sizeof(eth_hdr),err,err_info)) {
357 if (*err == WTAP_ERR_SHORT_READ) {
358 /* Subheader missing, not an ERF file */
359 return WTAP_OPEN_NOT_MINE;
361 return WTAP_OPEN_ERROR;
363 packet_size -= (guint32)sizeof(eth_hdr);
369 /* The file_seek function do not return an error if the end of file
370 is reached whereas the record is truncated */
371 if (packet_size > WTAP_MAX_PACKET_SIZE) {
373 * Probably a corrupt capture file or a file that's not an ERF file
374 * but that passed earlier tests.
376 return WTAP_OPEN_NOT_MINE;
378 buffer=(gchar *)g_malloc(packet_size);
379 r = wtap_read_bytes(wth->fh, buffer, packet_size, err, err_info);
383 if (*err != WTAP_ERR_SHORT_READ) {
385 return WTAP_OPEN_ERROR;
387 /* ERF record too short, accept the file,
388 only if the very first records have been successfully checked */
389 if (i < MIN_RECORDS_FOR_ERF_CHECK) {
390 return WTAP_OPEN_NOT_MINE;
396 } /* records_for_erf_check */
398 if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) { /* rewind */
399 return WTAP_OPEN_ERROR;
402 /* This is an ERF file */
403 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_ERF;
404 wth->snapshot_length = 0; /* not available in header, only in frame */
407 * Use the encapsulation for ERF records.
409 wth->file_encap = WTAP_ENCAP_ERF;
411 wth->subtype_read = erf_read;
412 wth->subtype_seek_read = erf_seek_read;
413 wth->subtype_close = erf_close;
414 wth->file_tsprec = WTAP_TSPREC_NSEC;
416 wth->priv = erf_priv_create();
418 return WTAP_OPEN_MINE;
421 /* Read the next packet */
422 static gboolean erf_read(wtap *wth, int *err, gchar **err_info,
425 erf_header_t erf_header;
426 guint32 packet_size, bytes_read;
428 *data_offset = file_tell(wth->fh);
431 if (!erf_read_header(wth, wth->fh,
432 &wth->phdr, &erf_header,
433 err, err_info, &bytes_read, &packet_size)) {
437 if (!wtap_read_packet_bytes(wth->fh, wth->frame_buffer, packet_size,
442 * If MetaERF, frame buffer could hold the meta erf tags. Only look until
443 * we have seen a description of every interface.
445 if ((erf_header.type & 0x7F) == ERF_TYPE_META && packet_size > 0)
447 populate_summary_info((erf_t*) wth->priv, wth, &wth->phdr.pseudo_header, packet_size);
450 } while ( erf_header.type == ERF_TYPE_PAD );
455 static gboolean erf_seek_read(wtap *wth, gint64 seek_off,
456 struct wtap_pkthdr *phdr, Buffer *buf,
457 int *err, gchar **err_info)
459 erf_header_t erf_header;
462 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
466 if (!erf_read_header(wth, wth->random_fh, phdr, &erf_header,
467 err, err_info, NULL, &packet_size))
469 } while ( erf_header.type == ERF_TYPE_PAD );
471 return wtap_read_packet_bytes(wth->random_fh, buf, packet_size,
475 static gboolean erf_read_header(wtap *wth, FILE_T fh,
476 struct wtap_pkthdr *phdr,
477 erf_header_t *erf_header,
481 guint32 *packet_size)
483 union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
485 guint64 erf_exhdr_sw;
489 struct wtap_erf_eth_hdr eth_hdr;
492 int max = sizeof(pseudo_header->erf.ehdr_list)/sizeof(struct erf_ehdr);
495 guint8 source_id = 0;
497 gboolean host_id_found = FALSE;
499 if (!wtap_read_bytes_or_eof(fh, erf_header, sizeof(*erf_header), err, err_info)) {
502 if (bytes_read != NULL) {
503 *bytes_read = sizeof(*erf_header);
506 *packet_size = g_ntohs(erf_header->rlen) - (guint32)sizeof(*erf_header);
508 if (*packet_size > WTAP_MAX_PACKET_SIZE) {
510 * Probably a corrupt capture file; don't blow up trying
511 * to allocate space for an immensely-large packet.
513 *err = WTAP_ERR_BAD_FILE;
514 *err_info = g_strdup_printf("erf: File has %u-byte packet, bigger than maximum of %u",
515 *packet_size, WTAP_MAX_PACKET_SIZE);
519 if (*packet_size == 0) {
520 /* If this isn't a pad record, it's a corrupt packet; bail out */
521 if ((erf_header->type & 0x7F) != ERF_TYPE_PAD) {
522 *err = WTAP_ERR_BAD_FILE;
523 *err_info = g_strdup_printf("erf: File has 0 byte packet");
530 guint64 ts = pletoh64(&erf_header->ts);
532 /*if ((erf_header->type & 0x7f) != ERF_TYPE_META || wth->file_type_subtype != WTAP_FILE_TYPE_SUBTYPE_ERF) {*/
533 phdr->rec_type = REC_TYPE_PACKET;
535 * XXX: ERF_TYPE_META records should ideally be FT_SPECIFIC for display
536 * purposes, but currently ft_specific_record_phdr clashes with erf_mc_phdr
537 * and the PCAP-NG dumper assumes it is a PCAP-NG block type. Ideally we
538 * would register a block handler with PCAP-NG and write out the closest
539 * PCAP-NG block, or a custom block/MetaERF record.
545 * TODO: how to identify, distinguish and timestamp events?
546 * What to do about ENCAP_ERF in PCAP/PCAP-NG? Filetype dissector is
547 * chosen by wth->file_type_subtype?
549 /* For now just treat all MetaERF records as reports */
550 phdr->rec_type = REC_TYPE_FT_SPECIFIC_REPORT;
551 /* XXX: phdr ft_specific_record_phdr? */
554 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN|WTAP_HAS_INTERFACE_ID;
555 phdr->ts.secs = (long) (ts >> 32);
556 ts = ((ts & 0xffffffff) * 1000 * 1000 * 1000);
557 ts += (ts & 0x80000000) << 1; /* rounding */
558 phdr->ts.nsecs = ((int) (ts >> 32));
559 if (phdr->ts.nsecs >= 1000000000) {
560 phdr->ts.nsecs -= 1000000000;
564 if_num = erf_header->flags & 0x03;
567 /* Copy the ERF pseudo header */
568 memset(&pseudo_header->erf, 0, sizeof(pseudo_header->erf));
569 pseudo_header->erf.phdr.ts = pletoh64(&erf_header->ts);
570 pseudo_header->erf.phdr.type = erf_header->type;
571 pseudo_header->erf.phdr.flags = erf_header->flags;
572 pseudo_header->erf.phdr.rlen = g_ntohs(erf_header->rlen);
573 pseudo_header->erf.phdr.lctr = g_ntohs(erf_header->lctr);
574 pseudo_header->erf.phdr.wlen = g_ntohs(erf_header->wlen);
576 /* Copy the ERF extension header into the pseudo header */
577 type = erf_header->type;
579 if (!wtap_read_bytes(fh, &erf_exhdr, sizeof(erf_exhdr),
582 if (bytes_read != NULL)
583 *bytes_read += (guint32)sizeof(erf_exhdr);
584 *packet_size -= (guint32)sizeof(erf_exhdr);
585 skiplen += (guint32)sizeof(erf_exhdr);
586 erf_exhdr_sw = pntoh64(erf_exhdr);
588 memcpy(&pseudo_header->erf.ehdr_list[i].ehdr, &erf_exhdr_sw, sizeof(erf_exhdr_sw));
592 * XXX: Only want first Source ID and Host ID, and want to preserve HID n SID 0 (see
593 * erf_populate_interface)
595 switch (type & 0x7f) {
596 case ERF_EXT_HDR_TYPE_HOST_ID:
598 host_id = erf_exhdr_sw & ERF_EHDR_HOST_ID_MASK;
600 host_id_found = TRUE;
602 case ERF_EXT_HDR_TYPE_FLOW_ID:
604 source_id = (erf_exhdr_sw >> 48) & 0xff;
611 /* XXX: erf_priv pointer needs to change if used as common function for other dissectors! */
612 phdr->interface_id = (guint) erf_populate_interface((erf_t*) wth->priv, wth, pseudo_header, host_id, source_id, if_num);
614 switch (erf_header->type & 0x7F) {
617 case ERF_TYPE_RAW_LINK:
618 case ERF_TYPE_INFINIBAND:
619 case ERF_TYPE_INFINIBAND_LINK:
621 case ERF_TYPE_OPA_SNC:
622 case ERF_TYPE_OPA_9B:
625 phdr->len = g_htons(erf_header->wlen);
626 phdr->caplen = g_htons(erf_header->wlen);
632 case ERF_TYPE_HDLC_POS:
633 case ERF_TYPE_COLOR_HDLC_POS:
634 case ERF_TYPE_DSM_COLOR_HDLC_POS:
635 case ERF_TYPE_COLOR_HASH_POS:
641 case ERF_TYPE_COLOR_ETH:
642 case ERF_TYPE_DSM_COLOR_ETH:
643 case ERF_TYPE_COLOR_HASH_ETH:
644 if (!wtap_read_bytes(fh, ð_hdr, sizeof(eth_hdr), err, err_info))
646 if (bytes_read != NULL)
647 *bytes_read += (guint32)sizeof(eth_hdr);
648 *packet_size -= (guint32)sizeof(eth_hdr);
649 skiplen += (guint32)sizeof(eth_hdr);
650 pseudo_header->erf.subhdr.eth_hdr = eth_hdr;
653 case ERF_TYPE_MC_HDLC:
654 case ERF_TYPE_MC_RAW:
655 case ERF_TYPE_MC_ATM:
656 case ERF_TYPE_MC_RAW_CHANNEL:
657 case ERF_TYPE_MC_AAL5:
658 case ERF_TYPE_MC_AAL2:
659 case ERF_TYPE_COLOR_MC_HDLC_POS:
660 if (!wtap_read_bytes(fh, &mc_hdr, sizeof(mc_hdr), err, err_info))
662 if (bytes_read != NULL)
663 *bytes_read += (guint32)sizeof(mc_hdr);
664 *packet_size -= (guint32)sizeof(mc_hdr);
665 skiplen += (guint32)sizeof(mc_hdr);
666 pseudo_header->erf.subhdr.mc_hdr = g_ntohl(mc_hdr);
670 if (!wtap_read_bytes(fh, &aal2_hdr, sizeof(aal2_hdr), err, err_info))
672 if (bytes_read != NULL)
673 *bytes_read += (guint32)sizeof(aal2_hdr);
674 *packet_size -= (guint32)sizeof(aal2_hdr);
675 skiplen += (guint32)sizeof(aal2_hdr);
676 pseudo_header->erf.subhdr.aal2_hdr = g_ntohl(aal2_hdr);
679 case ERF_TYPE_IP_COUNTER:
680 case ERF_TYPE_TCP_FLOW_COUNTER:
681 /* unsupported, continue with default: */
683 *err = WTAP_ERR_UNSUPPORTED;
684 *err_info = g_strdup_printf("erf: unknown record encapsulation %u",
690 phdr->len = g_ntohs(erf_header->wlen);
691 phdr->caplen = MIN( g_ntohs(erf_header->wlen),
692 g_ntohs(erf_header->rlen) - (guint32)sizeof(*erf_header) - skiplen );
695 if (*packet_size > WTAP_MAX_PACKET_SIZE) {
697 * Probably a corrupt capture file; don't blow up trying
698 * to allocate space for an immensely-large packet.
700 *err = WTAP_ERR_BAD_FILE;
701 *err_info = g_strdup_printf("erf: File has %u-byte packet, bigger than maximum of %u",
702 *packet_size, WTAP_MAX_PACKET_SIZE);
709 static int wtap_wtap_encap_to_erf_encap(int encap)
712 for(i = 0; i < NUM_ERF_ENCAPS; i++){
713 if(erf_to_wtap_map[i].wtap_encap_value == encap)
714 return erf_to_wtap_map[i].erf_encap_value;
719 static gboolean erf_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pseudo_header, int * err)
721 guint8 erf_hdr[sizeof(struct erf_mc_phdr)];
722 guint8 erf_subhdr[sizeof(union erf_subhdr)];
723 guint8 ehdr[8*MAX_ERF_EHDR];
725 size_t subhdr_size = 0;
731 memset(&erf_hdr, 0, sizeof(erf_hdr));
732 phtolell(&erf_hdr[0], pseudo_header->erf.phdr.ts);
733 erf_hdr[8] = pseudo_header->erf.phdr.type;
734 erf_hdr[9] = pseudo_header->erf.phdr.flags;
735 phtons(&erf_hdr[10], pseudo_header->erf.phdr.rlen);
736 phtons(&erf_hdr[12], pseudo_header->erf.phdr.lctr);
737 phtons(&erf_hdr[14], pseudo_header->erf.phdr.wlen);
738 size = sizeof(struct erf_phdr);
740 switch(pseudo_header->erf.phdr.type & 0x7F) {
741 case ERF_TYPE_MC_HDLC:
742 case ERF_TYPE_MC_RAW:
743 case ERF_TYPE_MC_ATM:
744 case ERF_TYPE_MC_RAW_CHANNEL:
745 case ERF_TYPE_MC_AAL5:
746 case ERF_TYPE_MC_AAL2:
747 case ERF_TYPE_COLOR_MC_HDLC_POS:
748 phtonl(&erf_subhdr[0], pseudo_header->erf.subhdr.mc_hdr);
749 subhdr_size += (int)sizeof(struct erf_mc_hdr);
752 phtonl(&erf_subhdr[0], pseudo_header->erf.subhdr.aal2_hdr);
753 subhdr_size += (int)sizeof(struct erf_aal2_hdr);
756 case ERF_TYPE_COLOR_ETH:
757 case ERF_TYPE_DSM_COLOR_ETH:
758 case ERF_TYPE_COLOR_HASH_ETH:
759 memcpy(&erf_subhdr[0], &pseudo_header->erf.subhdr.eth_hdr, sizeof pseudo_header->erf.subhdr.eth_hdr);
760 subhdr_size += (int)sizeof(struct erf_eth_hdr);
770 if (!wtap_dump_file_write(wdh, erf_hdr, size, err))
772 wdh->bytes_dumped += size;
774 /*write out up to MAX_ERF_EHDR extension headers*/
775 has_more = pseudo_header->erf.phdr.type & 0x80;
776 if(has_more){ /*we have extension headers*/
778 phtonll(ehdr+(i*8), pseudo_header->erf.ehdr_list[i].ehdr);
779 if(i == MAX_ERF_EHDR-1) ehdr[i*8] = ehdr[i*8] & 0x7F;
780 has_more = ehdr[i*8] & 0x80;
782 }while(has_more && i < MAX_ERF_EHDR);
783 if (!wtap_dump_file_write(wdh, ehdr, 8*i, err))
785 wdh->bytes_dumped += 8*i;
788 if(!wtap_dump_file_write(wdh, erf_subhdr, subhdr_size, err))
790 wdh->bytes_dumped += subhdr_size;
795 static gboolean erf_dump(
797 const struct wtap_pkthdr *phdr,
800 gchar **err_info _U_)
802 const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
803 union wtap_pseudo_header other_phdr;
805 gint64 alignbytes = 0;
808 gboolean must_add_crc = FALSE;
809 guint32 crc32 = 0x00000000;
811 /* Don't write anything bigger than we're willing to read. */
812 if(phdr->caplen > WTAP_MAX_PACKET_SIZE) {
813 *err = WTAP_ERR_PACKET_TOO_LARGE;
817 if(wdh->encap == WTAP_ENCAP_PER_PACKET){
818 encap = phdr->pkt_encap;
823 if(encap == WTAP_ENCAP_ERF){
824 /* We've been handed an ERF record, so there's not much to do here. */
825 alignbytes = wdh->bytes_dumped + pseudo_header->erf.phdr.rlen;
827 if(!erf_write_phdr(wdh, encap, pseudo_header, err)) return FALSE;
829 if(!wtap_dump_file_write(wdh, pd, phdr->caplen, err)) return FALSE;
830 wdh->bytes_dumped += phdr->caplen;
832 /*XXX: this pads the record to its original length, which is fine in most
833 * cases. However with >MAX_ERF_EHDR unnecessary padding will be added, and
834 * if the record was truncated this will be incorrectly treated as payload.
835 * More than 8 extension headers is unusual though, only the first 8 are
836 * written out anyway and fixing properly would require major refactor.*/
837 while(wdh->bytes_dumped < alignbytes){
838 if(!wtap_dump_file_write(wdh, "", 1, err)) return FALSE;
844 /* We can only convert packet records. */
845 if (phdr->rec_type != REC_TYPE_PACKET) {
846 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
850 /*generate a fake header in other_phdr using data that we know*/
851 /*covert time erf timestamp format*/
852 other_phdr.erf.phdr.ts = ((guint64) phdr->ts.secs << 32) + (((guint64) phdr->ts.nsecs <<32) / 1000 / 1000 / 1000);
853 other_phdr.erf.phdr.type = wtap_wtap_encap_to_erf_encap(encap);
854 other_phdr.erf.phdr.flags = 0x4; /*vlen flag set because we're creating variable length records*/
855 other_phdr.erf.phdr.lctr = 0;
856 /*now we work out rlen, accounting for all the different headers and missing fcs(eth)*/
857 other_phdr.erf.phdr.rlen = phdr->caplen+16;
858 other_phdr.erf.phdr.wlen = phdr->len;
859 switch(other_phdr.erf.phdr.type){
861 other_phdr.erf.phdr.rlen += 2; /*2 bytes for erf eth_type*/
862 if (pseudo_header->eth.fcs_len != 4) {
863 /* Either this packet doesn't include the FCS
864 (pseudo_header->eth.fcs_len = 0), or we don't
865 know whether it has an FCS (= -1). We have to
867 if(!(phdr->caplen < phdr->len)){ /*don't add FCS if packet has been snapped off*/
868 crc32 = crc32_ccitt_seed(pd, phdr->caplen, 0xFFFFFFFF);
869 other_phdr.erf.phdr.rlen += 4; /*4 bytes for added checksum*/
870 other_phdr.erf.phdr.wlen += 4;
875 case ERF_TYPE_HDLC_POS:
876 /*we assume that it's missing a FCS checksum, make one up*/
877 if(!(phdr->caplen < phdr->len)){ /*unless of course, the packet has been snapped off*/
878 crc32 = crc32_ccitt_seed(pd, phdr->caplen, 0xFFFFFFFF);
879 other_phdr.erf.phdr.rlen += 4; /*4 bytes for added checksum*/
880 other_phdr.erf.phdr.wlen += 4;
881 must_add_crc = TRUE; /* XXX - these never have an FCS? */
888 alignbytes = (8 - (other_phdr.erf.phdr.rlen % 8)) % 8; /*calculate how much padding will be required */
889 if(phdr->caplen < phdr->len){ /*if packet has been snapped, we need to round down what we output*/
890 round_down = (8 - (guint)alignbytes) % 8;
891 other_phdr.erf.phdr.rlen -= round_down;
893 other_phdr.erf.phdr.rlen += (gint16)alignbytes;
896 if(!erf_write_phdr(wdh, WTAP_ENCAP_ERF, &other_phdr, err)) return FALSE;
897 if(!wtap_dump_file_write(wdh, pd, phdr->caplen - round_down, err)) return FALSE;
898 wdh->bytes_dumped += phdr->caplen - round_down;
900 /*add the 4 byte CRC if necessary*/
902 if(!wtap_dump_file_write(wdh, &crc32, 4, err)) return FALSE;
903 wdh->bytes_dumped += 4;
905 /*records should be 8byte aligned, so we add padding*/
907 for(i = (gint16)alignbytes; i > 0; i--){
908 if(!wtap_dump_file_write(wdh, "", 1, err)) return FALSE;
916 int erf_dump_can_write_encap(int encap)
919 if(encap == WTAP_ENCAP_PER_PACKET)
922 if (wtap_wtap_encap_to_erf_encap(encap) == -1)
923 return WTAP_ERR_UNWRITABLE_ENCAP;
928 int erf_dump_open(wtap_dumper *wdh, int *err)
930 wdh->subtype_write = erf_dump;
932 switch(wdh->file_type_subtype){
933 case WTAP_FILE_TYPE_SUBTYPE_ERF:
934 wdh->tsprecision = WTAP_TSPREC_NSEC;
937 *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
946 * TODO: Replace uses in pcapng and pcap with
947 * erf_read_header() and/or erf_populate_interface_from_header() and delete.
949 int erf_populate_interfaces(wtap *wth)
951 wtap_optionblock_t int_data;
952 wtapng_if_descr_mandatory_t* int_data_mand;
958 /* Preemptively create interface entries for 4 interfaces, since this is the max number in ERF */
959 for (i=0; i<4; i++) {
961 int_data = wtap_optionblock_create(WTAP_OPTION_BLOCK_IF_DESCR);
962 int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(int_data);
964 int_data_mand->wtap_encap = WTAP_ENCAP_ERF;
965 /* int_data.time_units_per_second = (1LL<<32); ERF format resolution is 2^-32, capture resolution is unknown */
966 int_data_mand->time_units_per_second = 1000000000; /* XXX Since Wireshark only supports down to nanosecond resolution we have to dilute to this */
967 int_data_mand->link_type = wtap_wtap_encap_to_pcap_encap(WTAP_ENCAP_ERF);
968 int_data_mand->snap_len = 65535; /* ERF max length */
970 /* XXX: if_IPv4addr opt 4 Interface network address and netmask.*/
971 /* XXX: if_IPv6addr opt 5 Interface network address and prefix length (stored in the last byte).*/
972 /* XXX: if_MACaddr opt 6 Interface Hardware MAC address (48 bits).*/
973 /* XXX: if_EUIaddr opt 7 Interface Hardware EUI address (64 bits)*/
974 wtap_optionblock_set_option_uint64(int_data, OPT_IDB_SPEED, 0); /* Unknown - XXX should be left at default? */
975 /* int_data.if_tsresol = 0xa0; ERF format resolution is 2^-32 = 0xa0, capture resolution is unknown */
976 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 */
978 /* XXX: if_tzone 10 Time zone for GMT support (TODO: specify better). */
980 /* XXX if_tsoffset; opt 14 A 64 bits integer value that specifies an offset (in seconds)...*/
981 /* Interface statistics */
982 int_data_mand->num_stat_entries = 0;
983 int_data_mand->interface_statistics = NULL;
985 wtap_optionblock_set_option_string_format(int_data, OPT_IDB_NAME, "Port %c", 'A'+i);
986 wtap_optionblock_set_option_string_format(int_data, OPT_IDB_DESCR, "ERF Interface Id %d (Port %c)", i, 'A'+i);
988 g_array_append_val(wth->interface_data, int_data);
994 int erf_get_source_from_header(union wtap_pseudo_header *pseudo_header, guint64 *host_id, guint8 *source_id)
1000 gboolean host_id_found = FALSE;
1002 if (!pseudo_header || !host_id || !source_id)
1008 has_more = pseudo_header->erf.phdr.type & 0x80;
1010 while (has_more && (i < MAX_ERF_EHDR)) {
1011 hdr = pseudo_header->erf.ehdr_list[i].ehdr;
1012 type = (guint8) (hdr >> 56);
1015 * XXX: Only want first Source ID and Host ID, and want to preserve HID n SID 0 (see
1016 * erf_populate_interface)
1018 switch (type & 0x7f) {
1019 case ERF_EXT_HDR_TYPE_HOST_ID:
1021 *host_id = hdr & ERF_EHDR_HOST_ID_MASK;
1023 host_id_found = TRUE;
1025 case ERF_EXT_HDR_TYPE_FLOW_ID:
1026 if (*source_id == 0)
1027 *source_id = (hdr >> 48) & 0xff;
1034 has_more = type & 0x80;
1041 int erf_populate_interface_from_header(erf_t *erf_priv, wtap *wth, union wtap_pseudo_header *pseudo_header)
1050 if_num = pseudo_header->erf.phdr.flags & 0x03;
1052 erf_get_source_from_header(pseudo_header, &host_id, &source_id);
1054 return erf_populate_interface(erf_priv, wth, pseudo_header, host_id, source_id, if_num);
1057 static struct erf_if_mapping* erf_find_interface_mapping(erf_t *erf_priv, guint64 host_id, guint8 source_id)
1059 struct erf_if_mapping if_map_lookup;
1064 if_map_lookup.host_id = host_id;
1065 if_map_lookup.source_id = source_id;
1067 return (struct erf_if_mapping*) g_hash_table_lookup(erf_priv->if_map, &if_map_lookup);
1070 static void erf_set_interface_descr(wtap_optionblock_t block, guint option_id, guint64 host_id, guint8 source_id, guint8 if_num, const gchar *descr)
1073 char sourceid_buf[16];
1074 /* Host XXXXXXXXXXXX,*/
1075 char hostid_buf[24];
1077 sourceid_buf[0] = '\0';
1078 hostid_buf[0] = '\0';
1081 g_snprintf(hostid_buf, sizeof(hostid_buf), " Host %012" G_GINT64_MODIFIER "x,", host_id);
1084 if (source_id > 0) {
1085 g_snprintf(sourceid_buf, sizeof(sourceid_buf), " Source %u,", source_id);
1089 wtap_optionblock_set_option_string_format(block, option_id, "%s (ERF%s%s Interface %d)", descr, hostid_buf, sourceid_buf, if_num);
1091 wtap_optionblock_set_option_string_format(block, option_id, "Port %c (ERF%s%s Interface %d)", 'A'+if_num, hostid_buf, sourceid_buf, if_num);
1095 static int erf_update_implicit_host_id(erf_t *erf_priv, wtap *wth, guint64 implicit_host_id)
1097 GHashTableIter iter;
1098 gpointer iter_value;
1099 GList* implicit_list = NULL;
1101 wtap_optionblock_t int_data;
1102 struct erf_if_mapping* if_map = NULL;
1108 erf_priv->implicit_host_id = implicit_host_id;
1111 * We need to update the descriptions of all the interfaces with no Host
1112 * ID to the correct Host ID.
1114 g_hash_table_iter_init(&iter, erf_priv->if_map);
1116 /* Remove the implicit mappings from the mapping table */
1117 while (g_hash_table_iter_next(&iter, &iter_value, NULL)) {
1118 if_map = (struct erf_if_mapping*) iter_value;
1119 if (if_map->host_id == 0) {
1120 /* XXX: Can't add while iterating hash table so use list instead */
1121 g_hash_table_iter_steal(&iter);
1122 implicit_list = g_list_append(implicit_list, if_map);
1126 if (implicit_list) {
1127 item = implicit_list;
1129 if_map = (struct erf_if_mapping*) item->data;
1130 for (i = 0; i < 4; i++) {
1131 if (if_map->interfaces[i].if_index >= 0) {
1132 /* XXX: this is a pointer! */
1133 int_data = g_array_index(wth->interface_data, wtap_optionblock_t, if_map->interfaces[i].if_index);
1134 erf_set_interface_descr(int_data, OPT_IDB_NAME, implicit_host_id, if_map->source_id, (guint8) i, if_map->interfaces[i].name);
1135 erf_set_interface_descr(int_data, OPT_IDB_DESCR, implicit_host_id, if_map->source_id, (guint8) i, if_map->interfaces[i].descr);
1138 /* Re-add the item under the implicit Host ID */
1139 if_map->host_id = implicit_host_id;
1140 /* g_hash_table_add() only exists since 2.32. */
1141 g_hash_table_replace(erf_priv->if_map, if_map, if_map);
1142 } while ((item = g_list_next(item)));
1144 g_list_free(implicit_list);
1150 int erf_populate_interface(erf_t *erf_priv, wtap *wth, union wtap_pseudo_header *pseudo_header, guint64 host_id, guint8 source_id, guint8 if_num)
1152 wtap_optionblock_t int_data;
1153 wtapng_if_descr_mandatory_t* int_data_mand;
1154 struct erf_if_mapping* if_map = NULL;
1156 if (!wth || !pseudo_header || !erf_priv || if_num > 3)
1159 if ((pseudo_header->erf.phdr.type & 0x7f) == ERF_TYPE_META) {
1161 * XXX: We assume there is only one Implicit Host ID. As a special case a first
1162 * Host ID extension header with Source ID 0 on a record does not change
1163 * the implicit Host ID. We respect this even though we support only one
1166 if (erf_priv->implicit_host_id == 0 && source_id > 0 && host_id != 0) {
1167 erf_update_implicit_host_id(erf_priv, wth, host_id);
1172 host_id = erf_priv->implicit_host_id;
1175 if_map = erf_find_interface_mapping(erf_priv, host_id, source_id);
1178 if_map = erf_if_mapping_create(host_id, source_id);
1179 /* g_hash_table_add() only exists since 2.32. */
1180 g_hash_table_replace(erf_priv->if_map, if_map, if_map);
1184 /* Return the existing interface if we have it */
1185 if (if_map->interfaces[if_num].if_index >= 0) {
1186 return if_map->interfaces[if_num].if_index;
1189 int_data = wtap_optionblock_create(WTAP_OPTION_BLOCK_IF_DESCR);
1190 int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(int_data);
1192 int_data_mand->wtap_encap = WTAP_ENCAP_ERF;
1193 /* int_data.time_units_per_second = (1LL<<32); ERF format resolution is 2^-32, capture resolution is unknown */
1194 int_data_mand->time_units_per_second = 1000000000; /* XXX Since Wireshark only supports down to nanosecond resolution we have to dilute to this */
1195 int_data_mand->link_type = wtap_wtap_encap_to_pcap_encap(WTAP_ENCAP_ERF);
1196 int_data_mand->snap_len = 65535; /* ERF max length */
1198 /* XXX: if_IPv4addr opt 4 Interface network address and netmask.*/
1199 /* XXX: if_IPv6addr opt 5 Interface network address and prefix length (stored in the last byte).*/
1200 /* XXX: if_MACaddr opt 6 Interface Hardware MAC address (48 bits).*/
1201 /* XXX: if_EUIaddr opt 7 Interface Hardware EUI address (64 bits)*/
1202 wtap_optionblock_set_option_uint64(int_data, OPT_IDB_SPEED, 0); /* Unknown - XXX should be left at default? */
1203 /* int_data.if_tsresol = 0xa0; ERF format resolution is 2^-32 = 0xa0, capture resolution is unknown */
1204 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 */
1205 /* XXX: if_tzone 10 Time zone for GMT support (TODO: specify better). */
1206 /* XXX if_tsoffset; opt 14 A 64 bits integer value that specifies an offset (in seconds)...*/
1207 /* Interface statistics */
1208 int_data_mand->num_stat_entries = 0;
1209 int_data_mand->interface_statistics = NULL;
1211 erf_set_interface_descr(int_data, OPT_IDB_NAME, host_id, source_id, if_num, NULL);
1212 erf_set_interface_descr(int_data, OPT_IDB_DESCR, host_id, source_id, if_num, NULL);
1214 if_map->interfaces[if_num].if_index = (int) wth->interface_data->len;
1215 g_array_append_val(wth->interface_data, int_data);
1217 return if_map->interfaces[if_num].if_index;
1220 static guint32 erf_meta_read_tag(struct erf_meta_tag* tag, guint8 *tag_ptr, guint32 remaining_len)
1224 guint32 tagtotallength;
1226 if (!tag_ptr || !tag || remaining_len < ERF_META_TAG_HEADERLEN)
1229 /* tagtype (2 bytes) */
1230 tagtype = pntoh16(&tag_ptr[0]);
1232 /* length (2 bytes) */
1233 taglength = pntoh16(&tag_ptr[2]);
1235 tagtotallength = ERF_META_TAG_ALIGNED_LENGTH(taglength);
1237 if (remaining_len < tagtotallength) {
1241 tag->type = tagtype;
1242 tag->length = taglength;
1243 tag->value = &tag_ptr[4];
1245 return tagtotallength;
1248 static int populate_capture_host_info(erf_t *erf_priv, wtap *wth, union wtap_pseudo_header *pseudo_header _U_, struct erf_meta_read_state *state)
1250 struct erf_meta_tag tag = {0, 0, NULL};
1252 wtap_optionblock_t shb_hdr;
1254 gchar* app_name = NULL;
1255 gchar* app_version = NULL;
1256 gchar* model = NULL;
1257 gchar* descr = NULL;
1259 gchar* modelcpu = NULL;
1260 guint32 tagtotallength;
1262 if (!wth || !state || !wth->shb_hdr)
1265 /* XXX: wth->shb_hdr is already created by different layer, using directly for now. */
1266 shb_hdr = wth->shb_hdr;
1268 while ((tagtotallength = erf_meta_read_tag(&tag, state->tag_ptr, state->remaining_len)) && !ERF_META_IS_SECTION(tag.type)) {
1269 switch (state->sectiontype) {
1270 case ERF_META_SECTION_CAPTURE:
1272 if (erf_priv->capture_metadata == TRUE) {
1277 case ERF_META_TAG_comment:
1278 wtap_optionblock_set_option_string(shb_hdr, OPT_COMMENT, tag.value, tag.length);
1283 case ERF_META_SECTION_HOST:
1285 if (erf_priv->host_metadata == TRUE) {
1290 case ERF_META_TAG_model:
1292 model = g_strndup((gchar*) tag.value, tag.length);
1294 case ERF_META_TAG_cpu:
1296 cpu = g_strndup((gchar*) tag.value, tag.length);
1298 case ERF_META_TAG_descr:
1300 descr = g_strndup((gchar*) tag.value, tag.length);
1302 case ERF_META_TAG_os:
1303 wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_OS, tag.value, tag.length);
1305 case ERF_META_TAG_app_name:
1307 app_name = g_strndup((gchar*) tag.value, tag.length);
1309 case ERF_META_TAG_app_version:
1310 g_free(app_version);
1311 app_version = g_strndup((gchar*) tag.value, tag.length);
1313 /* TODO: dag_version? */
1314 /* TODO: could concatenate comment(s)? */
1322 state->tag_ptr += tagtotallength;
1323 state->remaining_len -= tagtotallength;
1326 /* Post processing */
1329 /* If no app_version will just use app_name */
1331 tmp = g_strjoin(" ", app_name, app_version, NULL);
1332 wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_USERAPPL, tmp, strlen(tmp));
1336 g_free(app_version);
1341 /* For the hardware field show description followed by (model; cpu) */
1342 /* Build "Model; CPU" part */
1344 /* g_strjoin() would be nice to use here if the API didn't stop on the first NULL... */
1346 modelcpu = g_strconcat(model, "; ", cpu, NULL);
1349 /* avoid double-free */
1353 /* avoid double-free */
1358 /* Combine into "Description (Model; CPU)" */
1359 if (state->sectiontype == ERF_META_SECTION_HOST && descr) {
1361 wtap_optionblock_set_option_string_format(shb_hdr, OPT_SHB_HARDWARE, "%s (%s)", descr, modelcpu);
1363 wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_HARDWARE, descr, strlen(descr));
1366 } else if (modelcpu) {
1367 wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_HARDWARE, modelcpu, strlen(modelcpu));
1368 /*modelcpu = NULL;*/
1371 /* Free the fields we didn't end up using */
1377 if (state->sectiontype == ERF_META_SECTION_CAPTURE) {
1378 erf_priv->capture_metadata = TRUE;
1380 erf_priv->host_metadata = TRUE;
1386 static int populate_module_info(erf_t *erf_priv _U_, wtap *wth, union wtap_pseudo_header *pseudo_header _U_, struct erf_meta_read_state *state)
1388 struct erf_meta_tag tag = {0, 0, NULL};
1390 guint32 tagtotallength;
1395 if (state->if_map->module_metadata == TRUE) {
1399 while ((tagtotallength = erf_meta_read_tag(&tag, state->tag_ptr, state->remaining_len)) && !ERF_META_IS_SECTION(tag.type)) {
1401 case ERF_META_TAG_fcs_len:
1402 if (tag.length >= 4) {
1403 state->if_map->module_fcs_len = (gint8) pntoh32(tag.value);
1406 case ERF_META_TAG_snaplen:
1407 /* XXX: this is generally per stream */
1408 if (tag.length >= 4) {
1409 state->if_map->module_snaplen = pntoh32(tag.value);
1412 case ERF_META_TAG_filter:
1413 g_free(state->if_map->module_filter_str);
1414 state->if_map->module_filter_str = g_strndup((gchar*) tag.value, tag.length);
1418 state->tag_ptr += tagtotallength;
1419 state->remaining_len -= tagtotallength;
1422 state->if_map->module_metadata = TRUE;
1427 static int populate_interface_info(erf_t *erf_priv, wtap *wth, union wtap_pseudo_header *pseudo_header, struct erf_meta_read_state *state)
1429 struct erf_meta_tag tag = {0, 0, NULL};
1430 guint32 tagtotallength;
1431 int interface_index = -1;
1432 wtap_optionblock_t int_data = NULL;
1433 wtapng_if_descr_mandatory_t* int_data_mand = NULL;
1434 wtapng_if_descr_filter_t if_filter;
1436 struct erf_if_info* if_info = NULL;
1438 memset(&if_filter, 0, sizeof(if_filter));
1440 if (!wth || !state || !pseudo_header || !state->if_map)
1443 /* Section ID of interface is defined to match ERF interface id. */
1444 if_num = state->sectionid - 1;
1446 * Get or create the interface (there can be multiple interfaces in
1447 * a MetaERF record).
1449 if (if_num < 4) { /* Note: -1u > 4*/
1450 if_info = &state->if_map->interfaces[if_num];
1451 interface_index = if_info->if_index;
1453 /* Check if the interface information is still uninitialized */
1454 if (interface_index == -1) {
1455 guint8 *tag_ptr_tmp = state->tag_ptr;
1456 guint32 remaining_len_tmp = state->remaining_len;
1458 /* First iterate tags, checking we aren't looking at a timing port */
1460 * XXX: we deliberately only do this logic here rather than the per-packet
1461 * population function so that if somehow we do see packets for an
1462 * 'invalid' port the interface will be created at that time.
1464 while ((tagtotallength = erf_meta_read_tag(&tag, tag_ptr_tmp, remaining_len_tmp)) && !ERF_META_IS_SECTION(tag.type)) {
1465 if (tag.type == ERF_META_TAG_if_port_type) {
1466 if (tag.length >= 4 && pntoh32(tag.value) == 2) {
1467 /* This is a timing port, skip it from now on */
1468 /* XXX: should we skip all non-capture ports instead? */
1470 if_info->if_index = -2;
1471 interface_index = -2;
1473 } else if (tag.type == ERF_META_TAG_stream_num) {
1474 if (tag.length >= 4) {
1475 if_info->stream_num = (gint32) pntoh32(tag.value);
1479 tag_ptr_tmp += tagtotallength;
1480 remaining_len_tmp -= tagtotallength;
1483 /* If the interface is valid but uninitialized, create it */
1484 if (interface_index == -1) {
1485 interface_index = erf_populate_interface(erf_priv, wth, pseudo_header, state->if_map->host_id, state->if_map->source_id, (guint8) if_num);
1489 /* Get the wiretap interface metadata */
1490 if (interface_index >= 0) {
1491 int_data = g_array_index(wth->interface_data, wtap_optionblock_t, interface_index);
1492 int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(int_data);
1493 } else if (interface_index == -2) {
1494 /* timing/unknown port */
1502 * Bail if already have interface metadata or no interface to associate with.
1503 * We also don't support metadata for >4 interfaces per Host + Source
1504 * as we only use interface ID.
1506 if (!int_data || state->if_map->interface_metadata & (1 << if_num))
1509 while ((tagtotallength = erf_meta_read_tag(&tag, state->tag_ptr, state->remaining_len)) && !ERF_META_IS_SECTION(tag.type)) {
1511 case ERF_META_TAG_name:
1512 /* TODO: fall back to module "dev_name Port N"? */
1513 if (!if_info->name) {
1514 if_info->name = g_strndup((gchar*) tag.value, tag.length);
1515 erf_set_interface_descr(int_data, OPT_IDB_NAME, state->if_map->host_id, state->if_map->source_id, (guint8) if_num, if_info->name);
1517 /* If we have no description, also copy to wtap if_description */
1518 if (!if_info->descr) {
1519 erf_set_interface_descr(int_data, OPT_IDB_DESCR, state->if_map->host_id, state->if_map->source_id, (guint8) if_num, if_info->name);
1523 case ERF_META_TAG_descr:
1524 if (!if_info->descr) {
1525 if_info->descr = g_strndup((gchar*) tag.value, tag.length);
1526 erf_set_interface_descr(int_data, OPT_IDB_DESCR, state->if_map->host_id, state->if_map->source_id, (guint8) if_num, if_info->descr);
1528 /* If we have no name, also copy to wtap if_name */
1529 if (!if_info->name) {
1530 erf_set_interface_descr(int_data, OPT_IDB_NAME, state->if_map->host_id, state->if_map->source_id, (guint8) if_num, if_info->descr);
1534 case ERF_META_TAG_if_speed:
1535 if (tag.length >= 8)
1536 wtap_optionblock_set_option_uint64(int_data, OPT_IDB_SPEED, pntoh64(tag.value));
1538 case ERF_META_TAG_if_num:
1540 * XXX: We ignore this as Section ID must match the ERF ifid and
1541 * that is all we care about/have space for at the moment. if_num
1542 * is only really useful with >4 interfaces.
1544 /* TODO: might want to put this number in description */
1546 case ERF_META_TAG_fcs_len:
1547 if (tag.length >= 4) {
1548 wtap_optionblock_set_option_uint8(int_data, OPT_IDB_FCSLEN, (guint8) pntoh32(tag.value));
1549 if_info->set_flags.fcs_len = 1;
1552 case ERF_META_TAG_snaplen:
1553 /* XXX: this generally per stream */
1554 if (tag.length >= 4) {
1555 int_data_mand->snap_len = pntoh32(tag.value);
1556 if_info->set_flags.snaplen = 1;
1559 case ERF_META_TAG_comment:
1560 wtap_optionblock_set_option_string(int_data, OPT_COMMENT, tag.value, tag.length);
1562 case ERF_META_TAG_filter:
1563 if_filter.if_filter_str = g_strndup((gchar*) tag.value, tag.length);
1564 wtap_optionblock_set_option_custom(int_data, OPT_IDB_FILTER, &if_filter);
1565 if_info->set_flags.filter = 1;
1571 state->tag_ptr += tagtotallength;
1572 state->remaining_len -= tagtotallength;
1575 /* Post processing */
1577 * XXX: Assumes module defined first. It is higher in hierarchy so only set
1582 * XXX: Missing exposed existence/type-check. No way currently to check if
1583 * been set in the optionblock.
1585 if (state->if_map->module_filter_str && !if_info->set_flags.filter) {
1586 /* Duplicate because might use with multiple interfaces */
1587 if_filter.if_filter_str = g_strdup(state->if_map->module_filter_str);
1588 wtap_optionblock_set_option_custom(int_data, OPT_IDB_FILTER, &if_filter);
1590 * Don't set flag because stream is more specific than module. Interface
1591 * metadata bit is set so we don't look at the filter again regardless.
1595 if (state->if_map->module_fcs_len != -1 && !if_info->set_flags.fcs_len) {
1596 wtap_optionblock_set_option_uint8(int_data, OPT_IDB_FCSLEN, (guint8) state->if_map->module_fcs_len);
1597 if_info->set_flags.fcs_len = 1;
1600 if (state->if_map->module_snaplen != (guint32) -1 && !if_info->set_flags.snaplen) {
1601 int_data_mand->snap_len = pntoh32(tag.value);
1602 if_info->set_flags.snaplen = 1;
1605 state->interface_metadata |= 1 << if_num;
1610 static int populate_stream_info(erf_t *erf_priv _U_, wtap *wth, union wtap_pseudo_header *pseudo_header, struct erf_meta_read_state *state)
1612 struct erf_meta_tag tag = {0, 0, NULL};
1613 guint32 tagtotallength;
1614 int interface_index = -1;
1615 wtap_optionblock_t int_data = NULL;
1616 wtapng_if_descr_mandatory_t* int_data_mand = NULL;
1617 wtapng_if_descr_filter_t if_filter;
1619 gint32 stream_num = -1;
1620 guint8 *tag_ptr_tmp;
1621 guint32 remaining_len_tmp;
1622 struct erf_if_info* if_info = NULL;
1624 memset(&if_filter, 0, sizeof(if_filter));
1626 if (!wth || !pseudo_header || !state || !state->if_map)
1629 tag_ptr_tmp = state->tag_ptr;
1630 remaining_len_tmp = state->remaining_len;
1633 * XXX: We ignore parent section ID because it doesn't represent the
1634 * many-to-many relationship of interfaces and streams very well. The stream is
1635 * associated with all interfaces in the record that don't have a stream_num
1636 * that says otherwise.
1639 if (state->sectionid > 0 && state->sectionid != 0x7fff) {
1640 /* Section ID of stream is supposed to match stream_num. */
1641 stream_num = state->sectionid - 1;
1643 /* First iterate tags, looking for the stream number interfaces might associate with. */
1644 while ((tagtotallength = erf_meta_read_tag(&tag, tag_ptr_tmp, remaining_len_tmp)) && !ERF_META_IS_SECTION(tag.type)) {
1645 if (tag.type == ERF_META_TAG_stream_num) {
1646 if (tag.length >= 4) {
1647 stream_num = (gint32) pntoh32(tag.value);
1651 tag_ptr_tmp += tagtotallength;
1652 remaining_len_tmp -= tagtotallength;
1655 /* Otherwise assume the stream applies to all interfaces in the record */
1657 for (if_num = 0; if_num < 4; if_num++) {
1658 tag_ptr_tmp = state->tag_ptr;
1659 remaining_len_tmp = state->remaining_len;
1660 if_info = &state->if_map->interfaces[if_num];
1662 /* Check if we should be handling this interface */
1663 /* XXX: currently skips interfaces that are not in the record. */
1664 if (state->if_map->interface_metadata & (1 << if_num)
1665 || !(state->interface_metadata & (1 << if_num))) {
1669 if (if_info->stream_num != -1
1670 && if_info->stream_num != stream_num) {
1674 interface_index = if_info->if_index;
1675 /* Get the wiretap interface metadata */
1676 if (interface_index >= 0) {
1677 int_data = g_array_index(wth->interface_data, wtap_optionblock_t, interface_index);
1678 int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(int_data);
1685 while ((tagtotallength = erf_meta_read_tag(&tag, tag_ptr_tmp, remaining_len_tmp)) && !ERF_META_IS_SECTION(tag.type)) {
1687 case ERF_META_TAG_fcs_len:
1688 if (tag.length >= 4) {
1689 /* Use the largest fcslen of matching streams */
1690 gint8 fcs_len = (gint8) pntoh32(tag.value);
1691 guint8 old_fcs_len = 0;
1693 wtap_optionblock_get_option_uint8(int_data, OPT_IDB_FCSLEN, &old_fcs_len);
1694 if (fcs_len > old_fcs_len || !if_info->set_flags.fcs_len) {
1695 wtap_optionblock_set_option_uint8(int_data, OPT_IDB_FCSLEN, (guint8) pntoh32(tag.value));
1696 if_info->set_flags.fcs_len = 1;
1700 case ERF_META_TAG_snaplen:
1701 if (tag.length >= 4) {
1702 /* Use the largest snaplen of matching streams */
1703 guint32 snaplen = pntoh32(tag.value);
1705 if (snaplen > int_data_mand->snap_len || !if_info->set_flags.snaplen) {
1706 int_data_mand->snap_len = pntoh32(tag.value);
1707 if_info->set_flags.snaplen = 1;
1711 case ERF_META_TAG_filter:
1712 /* Override only if not set */
1713 if (!if_info->set_flags.filter) {
1714 if_filter.if_filter_str = g_strndup((gchar*) tag.value, tag.length);
1715 wtap_optionblock_set_option_custom(int_data, OPT_IDB_FILTER, &if_filter);
1716 if_info->set_flags.filter = 1;
1723 tag_ptr_tmp += tagtotallength;
1724 remaining_len_tmp -= tagtotallength;
1727 state->tag_ptr = tag_ptr_tmp;
1728 state->remaining_len = remaining_len_tmp;
1733 /* Populates the capture and interface information for display on the Capture File Properties */
1734 static int populate_summary_info(erf_t *erf_priv, wtap *wth, union wtap_pseudo_header *pseudo_header, guint32 packet_size)
1736 struct erf_meta_read_state state;
1737 struct erf_meta_read_state *state_post = NULL;
1740 GList *post_list = NULL;
1743 struct erf_meta_tag tag = {0, 0, NULL};
1744 guint32 tagtotallength;
1746 if (!erf_priv || !wth || !pseudo_header)
1749 memset(&state, 0, sizeof(struct erf_meta_read_state));
1751 erf_get_source_from_header(pseudo_header, &host_id, &source_id);
1754 host_id = erf_priv->implicit_host_id;
1757 state.if_map = erf_find_interface_mapping(erf_priv, host_id, source_id);
1759 if (!state.if_map) {
1760 state.if_map = erf_if_mapping_create(host_id, source_id);
1761 /* g_hash_table_add() only exists since 2.32. */
1762 g_hash_table_replace(erf_priv->if_map, state.if_map, state.if_map);
1767 * Skip the record if we already have enough metadata (seen one section for
1768 * each type for the source).
1770 if ((state.if_map->interface_metadata & 0x03)
1771 && erf_priv->host_metadata && erf_priv->capture_metadata) {
1775 state.tag_ptr = wth->frame_buffer->data;
1776 state.remaining_len = packet_size;
1778 /* Read until see next section tag */
1779 while ((tagtotallength = erf_meta_read_tag(&tag, state.tag_ptr, state.remaining_len))) {
1781 * Skip until we get to the next section tag (which could be the current tag
1782 * after an empty section or successful parsing).
1784 if (!ERF_META_IS_SECTION(tag.type)) {
1786 state.tag_ptr += tagtotallength;
1787 state.remaining_len -= tagtotallength;
1792 * We are now looking at the next section (and would have exited the loop
1793 * if we reached the end).
1796 /* Update parent section. Implicit grouping is by a change in section except Interface and Stream. */
1797 if (tag.type != state.sectiontype) {
1798 if ((tag.type == ERF_META_SECTION_STREAM && state.sectiontype == ERF_META_SECTION_INTERFACE) ||
1799 (tag.type == ERF_META_SECTION_INTERFACE && state.sectiontype == ERF_META_SECTION_STREAM)) {
1802 state.parentsectiontype = state.sectiontype;
1803 state.parentsectionid = state.sectionid;
1807 /* Update with new sectiontype */
1808 state.sectiontype = tag.type;
1809 if (tag.length >= 4) {
1810 state.sectionid = pntoh16(tag.value);
1812 state.sectionid = 0;
1815 /* Adjust offset to that of first tag in section */
1816 state.tag_ptr += tagtotallength;
1817 state.remaining_len -= tagtotallength;
1819 if ((tagtotallength = erf_meta_read_tag(&tag, state.tag_ptr, state.remaining_len))) {
1821 * Process parent section tag if present (which must be the first tag in
1824 if (tag.type == ERF_META_TAG_parent_section && tag.length >= 4) {
1825 state.parentsectiontype = pntoh16(tag.value);
1826 state.parentsectionid = pntoh16(&tag.value[2]);
1830 /* Skip empty sections (includes if above read fails) */
1831 if (ERF_META_IS_SECTION(tag.type)) {
1836 * Skip sections that don't apply to the general set of records
1837 * (extension point for per-packet/event metadata).
1839 if (state.sectionid & 0x8000) {
1844 * Start at first tag in section, makes loop
1845 * simpler in called functions too. Also makes iterating after failure
1848 switch (state.sectiontype) {
1849 case ERF_META_SECTION_CAPTURE:
1850 case ERF_META_SECTION_HOST:
1851 /* TODO: use return code */
1852 populate_capture_host_info(erf_priv, wth, pseudo_header, &state);
1854 case ERF_META_SECTION_MODULE:
1855 populate_module_info(erf_priv, wth, pseudo_header, &state);
1857 case ERF_META_SECTION_INTERFACE:
1858 populate_interface_info(erf_priv, wth, pseudo_header, &state);
1860 case ERF_META_SECTION_STREAM:
1862 * XXX: Treat streams specially in case the stream information appears
1863 * before the interface information, as we associate them to interface
1866 post_list = g_list_append(post_list, g_memdup(&state, sizeof(struct erf_meta_read_state)));
1868 case ERF_META_SECTION_SOURCE:
1869 case ERF_META_SECTION_DNS:
1871 /* TODO: Not yet implemented */
1876 /* Process streams last */
1880 state_post = (struct erf_meta_read_state*) item->data;
1881 switch (state_post->sectiontype) {
1882 case ERF_META_SECTION_STREAM:
1883 populate_stream_info(erf_priv, wth, pseudo_header, state_post);
1886 } while ((item = g_list_next(item)));
1887 /* g_list_free_full() only exists since 2.28. */
1888 g_list_foreach(post_list, erf_free_data, NULL);
1889 g_list_free(post_list);
1893 * Update known metadata so we only examine the first set of metadata. Need to
1894 * do this here so can have interface and stream in same record.
1896 state.if_map->interface_metadata |= state.interface_metadata;
1901 static void erf_close(wtap *wth)
1903 erf_t* erf_priv = (erf_t*)wth->priv;
1905 erf_priv_free(erf_priv);
1906 /* XXX: Prevent double free by wtap_close() */
1911 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1916 * indent-tabs-mode: nil
1919 * vi: set shiftwidth=2 tabstop=8 expandtab:
1920 * :indentSize=2:tabSize=8:noTabs=true: