Make wtap_optionblock_foreach_option public.
[metze/wireshark/wip.git] / wiretap / erf.c
1 /*
2  * Copyright (c) 2003 Endace Technology Ltd, Hamilton, New Zealand.
3  * All rights reserved.
4  *
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/.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  *  1. Redistributions of source code must retain the above copyright notice,
13  *  this list of conditions and the following disclaimer.
14  *
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.
18  *
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
21  *  permission.
22  *
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.
33  */
34
35 /*
36  * erf - Endace ERF (Extensible Record Format)
37  *
38  * See
39  *
40  *      http://www.endace.com/support/EndaceRecordFormat.pdf
41  *      (mirror: https://bugs.wireshark.org/bugzilla/attachment.cgi?id=4333) (bug #4484)
42  */
43
44 #include "config.h"
45
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include <glib.h>
50
51 #include <wsutil/crc32.h>
52
53 #include "wtap-int.h"
54 #include "file_wrappers.h"
55 #include "pcap-encap.h"
56 #include "pcapng.h"
57 #include "erf.h"
58
59 static gboolean erf_read_header(wtap *wth, FILE_T fh,
60                                 struct wtap_pkthdr *phdr,
61                                 erf_header_t *erf_header,
62                                 int *err,
63                                 gchar **err_info,
64                                 guint32 *bytes_read,
65                                 guint32 *packet_size);
66 static gboolean erf_read(wtap *wth, int *err, gchar **err_info,
67                          gint64 *data_offset);
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);
73
74 static const struct {
75   int erf_encap_value;
76   int wtap_encap_value;
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*/
86 };
87
88 #define NUM_ERF_ENCAPS (sizeof erf_to_wtap_map / sizeof erf_to_wtap_map[0])
89
90 #define ERF_META_TAG_HEADERLEN 4
91 #define ERF_META_TAG_ALIGNED_LENGTH(taglength)  ((((guint32)taglength + 0x3U) & ~0x3U) + ERF_META_TAG_HEADERLEN)
92
93 struct erf_if_info {
94   int if_index;
95   gchar *name;
96   gchar *descr;
97   int stream_num;
98   struct {
99     guint filter:1;
100     guint fcs_len:1;
101     guint snaplen:1;
102   } set_flags;
103 };
104
105 struct erf_if_mapping {
106   guint64 host_id;
107   guint8 source_id;
108   struct erf_if_info interfaces[4];
109
110   gchar *module_filter_str;
111   gint8 module_fcs_len;
112   guint32 module_snaplen;
113   int interface_metadata;
114   gboolean module_metadata;
115 };
116
117 struct erf_meta_tag {
118   guint16 type;
119   guint16 length;
120   guint8 *value;
121 };
122
123 struct erf_meta_read_state {
124   guint8 *tag_ptr;
125   guint32 remaining_len;
126
127   struct erf_if_mapping *if_map;
128
129   guint16 sectiontype;
130   guint16 sectionid;
131   guint16 parentsectiontype;
132   guint16 parentsectionid;
133
134   int interface_metadata;
135 };
136
137 static gboolean erf_if_mapping_equal(gconstpointer a, gconstpointer b)
138 {
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;
141
142   return if_map_a->source_id == if_map_b->source_id && if_map_a->host_id == if_map_b->host_id;
143 }
144
145 static guint erf_if_mapping_hash(gconstpointer key)
146 {
147   const struct erf_if_mapping *if_map = (const struct erf_if_mapping*) key;
148
149   return (((guint) if_map->host_id) << 16) | if_map->source_id;
150 }
151
152 static void erf_if_mapping_destroy(gpointer key)
153 {
154   int i = 0;
155   struct erf_if_mapping *if_map = (struct erf_if_mapping*) key;
156
157   for (i = 0; i < 4; i++) {
158     g_free(if_map->interfaces[i].name);
159     g_free(if_map->interfaces[i].descr);
160   }
161
162   g_free(if_map->module_filter_str);
163   g_free(if_map);
164 }
165
166 static struct erf_if_mapping* erf_if_mapping_create(guint64 host_id, guint8 source_id)
167 {
168   int i = 0;
169   struct erf_if_mapping *if_map = NULL;
170
171   if_map = (struct erf_if_mapping*) g_malloc(sizeof(struct erf_if_mapping));
172   memset(if_map, 0, sizeof(struct erf_if_mapping));
173
174   if_map->host_id = host_id;
175   if_map->source_id = source_id;
176
177   for (i = 0; i < 4; i++) {
178     if_map->interfaces[i].if_index = -1;
179     if_map->interfaces[i].stream_num = -1;
180   }
181
182   if_map->module_fcs_len = -1;
183   if_map->module_snaplen = (guint32) -1;
184   /* everything else 0 by memset */
185
186   return if_map;
187 }
188
189 erf_t *erf_priv_create(void)
190 {
191   erf_t *erf_priv;
192
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;
198
199   return erf_priv;
200 }
201
202 erf_t* erf_priv_free(erf_t* erf_priv)
203 {
204   if (erf_priv)
205   {
206     g_hash_table_destroy(erf_priv->if_map);
207     g_free(erf_priv);
208   }
209
210   return NULL;
211 }
212
213 static void
214 erf_free_data(gpointer data, gpointer user_data _U_)
215 {
216     g_free(data);
217 }
218
219
220 extern wtap_open_return_val erf_open(wtap *wth, int *err, gchar **err_info)
221 {
222   int              i, n, records_for_erf_check = RECORDS_FOR_ERF_CHECK;
223   int              valid_prev                  = 0;
224   char            *s;
225   erf_timestamp_t  prevts,ts;
226   erf_header_t     header;
227   guint32          mc_hdr;
228   struct erf_eth_hdr eth_hdr;
229   guint32          packet_size;
230   guint16          rlen;
231   guint64          erf_ext_header;
232   guint8           type;
233   gboolean         r;
234   gchar *          buffer;
235
236   memset(&prevts, 0, sizeof(prevts));
237
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;
242     }
243   }
244
245   /*
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
248    * records.
249    */
250
251   for (i = 0; i < records_for_erf_check; i++) {  /* records_for_erf_check */
252
253     if (!wtap_read_bytes_or_eof(wth->fh,&header,sizeof(header),err,err_info)) {
254       if (*err == 0) {
255         /* EOF - all records have been successfully checked, accept the file */
256         break;
257       }
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;
263         } else {
264           /* BREAK, the last record is too short, and will be ignored */
265           break;
266         }
267       } else {
268         return WTAP_OPEN_ERROR;
269       }
270     }
271
272     rlen=g_ntohs(header.rlen);
273
274     /* fail on invalid record type, invalid rlen, timestamps decreasing, or incrementing too far */
275
276     /* Test valid rlen >= 16 */
277     if (rlen < 16) {
278       return WTAP_OPEN_NOT_MINE;
279     }
280
281     packet_size = rlen - (guint32)sizeof(header);
282     if (packet_size > WTAP_MAX_PACKET_SIZE) {
283       /*
284        * Probably a corrupt capture file or a file that's not an ERF file
285        * but that passed earlier tests.
286        */
287       return WTAP_OPEN_NOT_MINE;
288     }
289
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;
294       }
295       continue;
296     }
297
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;
302     }
303
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;
308       }
309     }
310
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;
314     }
315
316     memcpy(&prevts, &ts, sizeof(prevts));
317
318     /* Read over the extension headers */
319     type = header.type;
320     while (type & 0x80){
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;
325         }
326         return WTAP_OPEN_ERROR;
327       }
328       packet_size -= (guint32)sizeof(erf_ext_header);
329       memcpy(&type, &erf_ext_header, sizeof(type));
330     }
331
332
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;
347           }
348           return WTAP_OPEN_ERROR;
349         }
350         packet_size -= (guint32)sizeof(mc_hdr);
351         break;
352       case ERF_TYPE_ETH:
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,&eth_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;
360           }
361           return WTAP_OPEN_ERROR;
362         }
363         packet_size -= (guint32)sizeof(eth_hdr);
364         break;
365       default:
366         break;
367     }
368
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) {
372       /*
373        * Probably a corrupt capture file or a file that's not an ERF file
374        * but that passed earlier tests.
375        */
376       return WTAP_OPEN_NOT_MINE;
377     }
378     buffer=(gchar *)g_malloc(packet_size);
379     r = wtap_read_bytes(wth->fh, buffer, packet_size, err, err_info);
380     g_free(buffer);
381
382     if (!r) {
383       if (*err != WTAP_ERR_SHORT_READ) {
384         /* A real error */
385         return WTAP_OPEN_ERROR;
386       }
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;
391       }
392     }
393
394     valid_prev = 1;
395
396   } /* records_for_erf_check */
397
398   if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) {   /* rewind */
399     return WTAP_OPEN_ERROR;
400   }
401
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 */
405
406   /*
407    * Use the encapsulation for ERF records.
408    */
409   wth->file_encap = WTAP_ENCAP_ERF;
410
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;
415
416   wth->priv = erf_priv_create();
417
418   return WTAP_OPEN_MINE;
419 }
420
421 /* Read the next packet */
422 static gboolean erf_read(wtap *wth, int *err, gchar **err_info,
423                          gint64 *data_offset)
424 {
425   erf_header_t erf_header;
426   guint32      packet_size, bytes_read;
427
428   *data_offset = file_tell(wth->fh);
429
430   do {
431     if (!erf_read_header(wth, wth->fh,
432                          &wth->phdr, &erf_header,
433                          err, err_info, &bytes_read, &packet_size)) {
434       return FALSE;
435     }
436
437     if (!wtap_read_packet_bytes(wth->fh, wth->frame_buffer, packet_size,
438                                 err, err_info))
439       return FALSE;
440
441     /*
442      * If MetaERF, frame buffer could hold the meta erf tags. Only look until
443      * we have seen a description of every interface.
444      */
445     if ((erf_header.type & 0x7F) == ERF_TYPE_META && packet_size > 0)
446     {
447       populate_summary_info((erf_t*) wth->priv, wth, &wth->phdr.pseudo_header, packet_size);
448     }
449
450   } while ( erf_header.type == ERF_TYPE_PAD );
451
452   return TRUE;
453 }
454
455 static gboolean erf_seek_read(wtap *wth, gint64 seek_off,
456                               struct wtap_pkthdr *phdr, Buffer *buf,
457                               int *err, gchar **err_info)
458 {
459   erf_header_t erf_header;
460   guint32      packet_size;
461
462   if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
463     return FALSE;
464
465   do {
466     if (!erf_read_header(wth, wth->random_fh, phdr, &erf_header,
467                          err, err_info, NULL, &packet_size))
468       return FALSE;
469   } while ( erf_header.type == ERF_TYPE_PAD );
470
471   return wtap_read_packet_bytes(wth->random_fh, buf, packet_size,
472                                 err, err_info);
473 }
474
475 static gboolean erf_read_header(wtap *wth, FILE_T fh,
476                                 struct wtap_pkthdr *phdr,
477                                 erf_header_t *erf_header,
478                                 int *err,
479                                 gchar **err_info,
480                                 guint32 *bytes_read,
481                                 guint32 *packet_size)
482 {
483   union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
484   guint8  erf_exhdr[8];
485   guint64 erf_exhdr_sw;
486   guint8  type    = 0;
487   guint32 mc_hdr;
488   guint32 aal2_hdr;
489   struct wtap_erf_eth_hdr eth_hdr;
490   guint32 skiplen = 0;
491   int     i       = 0;
492   int     max     = sizeof(pseudo_header->erf.ehdr_list)/sizeof(struct erf_ehdr);
493
494   guint64 host_id  = 0;
495   guint8 source_id = 0;
496   guint8 if_num    = 0;
497   gboolean host_id_found = FALSE;
498
499   if (!wtap_read_bytes_or_eof(fh, erf_header, sizeof(*erf_header), err, err_info)) {
500     return FALSE;
501   }
502   if (bytes_read != NULL) {
503     *bytes_read = sizeof(*erf_header);
504   }
505
506   *packet_size =  g_ntohs(erf_header->rlen) - (guint32)sizeof(*erf_header);
507
508   if (*packet_size > WTAP_MAX_PACKET_SIZE) {
509     /*
510      * Probably a corrupt capture file; don't blow up trying
511      * to allocate space for an immensely-large packet.
512      */
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);
516     return FALSE;
517   }
518
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");
524
525       return FALSE;
526     }
527   }
528
529   {
530     guint64 ts = pletoh64(&erf_header->ts);
531
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;
534     /*
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.
540      *
541      */
542 #if 0
543     } else {
544       /*
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?
548        */
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? */
552     }
553 #endif
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;
561       phdr->ts.secs += 1;
562     }
563
564     if_num = erf_header->flags & 0x03;
565   }
566
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);
575
576   /* Copy the ERF extension header into the pseudo header */
577   type = erf_header->type;
578   while (type & 0x80){
579     if (!wtap_read_bytes(fh, &erf_exhdr, sizeof(erf_exhdr),
580                          err, err_info))
581       return FALSE;
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);
587     if (i < max)
588       memcpy(&pseudo_header->erf.ehdr_list[i].ehdr, &erf_exhdr_sw, sizeof(erf_exhdr_sw));
589     type = erf_exhdr[0];
590
591     /*
592      * XXX: Only want first Source ID and Host ID, and want to preserve HID n SID 0 (see
593      * erf_populate_interface)
594      */
595     switch (type & 0x7f) {
596       case ERF_EXT_HDR_TYPE_HOST_ID:
597         if (!host_id_found)
598           host_id = erf_exhdr_sw & ERF_EHDR_HOST_ID_MASK;
599
600         host_id_found = TRUE;
601         /* Fall through */
602       case ERF_EXT_HDR_TYPE_FLOW_ID:
603         if (!source_id)
604           source_id = (erf_exhdr_sw >> 48) & 0xff;
605         break;
606     }
607
608     i++;
609   }
610
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);
613
614   switch (erf_header->type & 0x7F) {
615     case ERF_TYPE_IPV4:
616     case ERF_TYPE_IPV6:
617     case ERF_TYPE_RAW_LINK:
618     case ERF_TYPE_INFINIBAND:
619     case ERF_TYPE_INFINIBAND_LINK:
620     case ERF_TYPE_META:
621     case ERF_TYPE_OPA_SNC:
622     case ERF_TYPE_OPA_9B:
623 #if 0
624       {
625         phdr->len =  g_htons(erf_header->wlen);
626         phdr->caplen = g_htons(erf_header->wlen);
627       }
628       return TRUE;
629 #endif
630       break;
631     case ERF_TYPE_PAD:
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:
636     case ERF_TYPE_ATM:
637     case ERF_TYPE_AAL5:
638       break;
639
640     case ERF_TYPE_ETH:
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, &eth_hdr, sizeof(eth_hdr), err, err_info))
645         return FALSE;
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;
651       break;
652
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))
661         return FALSE;
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);
667       break;
668
669     case ERF_TYPE_AAL2:
670       if (!wtap_read_bytes(fh, &aal2_hdr, sizeof(aal2_hdr), err, err_info))
671         return FALSE;
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);
677       break;
678
679     case ERF_TYPE_IP_COUNTER:
680     case ERF_TYPE_TCP_FLOW_COUNTER:
681       /* unsupported, continue with default: */
682     default:
683       *err = WTAP_ERR_UNSUPPORTED;
684       *err_info = g_strdup_printf("erf: unknown record encapsulation %u",
685                                   erf_header->type);
686       return FALSE;
687   }
688
689   {
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 );
693   }
694
695   if (*packet_size > WTAP_MAX_PACKET_SIZE) {
696     /*
697      * Probably a corrupt capture file; don't blow up trying
698      * to allocate space for an immensely-large packet.
699      */
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);
703     return FALSE;
704   }
705
706   return TRUE;
707 }
708
709 static int wtap_wtap_encap_to_erf_encap(int encap)
710 {
711   unsigned int i;
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;
715   }
716   return -1;
717 }
718
719 static gboolean erf_write_phdr(wtap_dumper *wdh, int encap, const union wtap_pseudo_header *pseudo_header, int * err)
720 {
721   guint8 erf_hdr[sizeof(struct erf_mc_phdr)];
722   guint8 erf_subhdr[sizeof(union erf_subhdr)];
723   guint8 ehdr[8*MAX_ERF_EHDR];
724   size_t size        = 0;
725   size_t subhdr_size = 0;
726   int    i           = 0;
727   guint8 has_more    = 0;
728
729   switch(encap){
730     case WTAP_ENCAP_ERF:
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);
739
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);
750           break;
751         case ERF_TYPE_AAL2:
752           phtonl(&erf_subhdr[0], pseudo_header->erf.subhdr.aal2_hdr);
753           subhdr_size += (int)sizeof(struct erf_aal2_hdr);
754           break;
755         case ERF_TYPE_ETH:
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);
761           break;
762         default:
763           break;
764       }
765       break;
766     default:
767       return FALSE;
768
769   }
770   if (!wtap_dump_file_write(wdh, erf_hdr, size, err))
771     return FALSE;
772   wdh->bytes_dumped += size;
773
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*/
777     do{
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;
781       i++;
782     }while(has_more && i < MAX_ERF_EHDR);
783     if (!wtap_dump_file_write(wdh, ehdr, 8*i, err))
784       return FALSE;
785     wdh->bytes_dumped += 8*i;
786   }
787
788   if(!wtap_dump_file_write(wdh, erf_subhdr, subhdr_size, err))
789     return FALSE;
790   wdh->bytes_dumped += subhdr_size;
791
792   return TRUE;
793 }
794
795 static gboolean erf_dump(
796     wtap_dumper                    *wdh,
797     const struct wtap_pkthdr       *phdr,
798     const guint8                   *pd,
799     int                            *err,
800     gchar                          **err_info _U_)
801 {
802   const union wtap_pseudo_header *pseudo_header = &phdr->pseudo_header;
803   union wtap_pseudo_header other_phdr;
804   int      encap;
805   gint64   alignbytes   = 0;
806   int      i;
807   int      round_down   = 0;
808   gboolean must_add_crc = FALSE;
809   guint32  crc32        = 0x00000000;
810
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;
814     return FALSE;
815   }
816
817   if(wdh->encap == WTAP_ENCAP_PER_PACKET){
818     encap = phdr->pkt_encap;
819   }else{
820     encap = wdh->encap;
821   }
822
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;
826
827     if(!erf_write_phdr(wdh, encap, pseudo_header, err)) return FALSE;
828
829     if(!wtap_dump_file_write(wdh, pd, phdr->caplen, err)) return FALSE;
830     wdh->bytes_dumped += phdr->caplen;
831
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;
839       wdh->bytes_dumped++;
840     }
841     return TRUE;
842   }
843
844   /* We can only convert packet records. */
845   if (phdr->rec_type != REC_TYPE_PACKET) {
846     *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
847     return FALSE;
848   }
849
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){
860     case ERF_TYPE_ETH:
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
866            synthesize an FCS.*/
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;
871           must_add_crc = TRUE;
872         }
873       }
874       break;
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? */
882       }
883       break;
884     default:
885       break;
886   }
887
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;
892   }else{
893     other_phdr.erf.phdr.rlen += (gint16)alignbytes;
894   }
895
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;
899
900   /*add the 4 byte CRC if necessary*/
901   if(must_add_crc){
902     if(!wtap_dump_file_write(wdh, &crc32, 4, err)) return FALSE;
903     wdh->bytes_dumped += 4;
904   }
905   /*records should be 8byte aligned, so we add padding*/
906   if(round_down == 0){
907     for(i = (gint16)alignbytes; i > 0; i--){
908       if(!wtap_dump_file_write(wdh, "", 1, err)) return FALSE;
909       wdh->bytes_dumped++;
910     }
911   }
912
913   return TRUE;
914 }
915
916 int erf_dump_can_write_encap(int encap)
917 {
918
919   if(encap == WTAP_ENCAP_PER_PACKET)
920     return 0;
921
922   if (wtap_wtap_encap_to_erf_encap(encap) == -1)
923     return WTAP_ERR_UNWRITABLE_ENCAP;
924
925   return 0;
926 }
927
928 int erf_dump_open(wtap_dumper *wdh, int *err)
929 {
930   wdh->subtype_write = erf_dump;
931
932   switch(wdh->file_type_subtype){
933     case WTAP_FILE_TYPE_SUBTYPE_ERF:
934       wdh->tsprecision = WTAP_TSPREC_NSEC;
935       break;
936     default:
937       *err = WTAP_ERR_UNWRITABLE_FILE_TYPE;
938       return FALSE;
939       break;
940   }
941
942   return TRUE;
943 }
944
945 /*
946  * TODO: Replace uses in pcapng and pcap with
947  * erf_read_header() and/or erf_populate_interface_from_header() and delete.
948  */
949 int erf_populate_interfaces(wtap *wth)
950 {
951   wtap_optionblock_t int_data;
952   wtapng_if_descr_mandatory_t* int_data_mand;
953   int i;
954
955   if (!wth)
956     return -1;
957
958   /* Preemptively create interface entries for 4 interfaces, since this is the max number in ERF */
959   for (i=0; i<4; i++) {
960
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);
963
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 */
969
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 */
977
978     /* XXX: if_tzone      10  Time zone for GMT support (TODO: specify better). */
979
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;
984
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);
987
988     g_array_append_val(wth->interface_data, int_data);
989   }
990
991   return 0;
992 }
993
994 int erf_get_source_from_header(union wtap_pseudo_header *pseudo_header, guint64 *host_id, guint8 *source_id)
995 {
996   guint8   type;
997   guint8   has_more;
998   guint64  hdr;
999   int      i             = 0;
1000   gboolean host_id_found = FALSE;
1001
1002   if (!pseudo_header || !host_id || !source_id)
1003       return -1;
1004
1005   *host_id = 0;
1006   *source_id = 0;
1007
1008   has_more = pseudo_header->erf.phdr.type & 0x80;
1009
1010   while (has_more && (i < MAX_ERF_EHDR)) {
1011     hdr = pseudo_header->erf.ehdr_list[i].ehdr;
1012     type = (guint8) (hdr >> 56);
1013
1014     /*
1015      * XXX: Only want first Source ID and Host ID, and want to preserve HID n SID 0 (see
1016      * erf_populate_interface)
1017      */
1018     switch (type & 0x7f) {
1019       case ERF_EXT_HDR_TYPE_HOST_ID:
1020         if (!host_id_found)
1021           *host_id = hdr & ERF_EHDR_HOST_ID_MASK;
1022
1023         host_id_found = TRUE;
1024         /* Fall through */
1025       case ERF_EXT_HDR_TYPE_FLOW_ID:
1026         if (*source_id == 0)
1027           *source_id = (hdr >> 48) & 0xff;
1028         break;
1029     }
1030
1031     if (host_id_found)
1032       break;
1033
1034     has_more = type & 0x80;
1035     i += 1;
1036   }
1037
1038   return 0;
1039 }
1040
1041 int erf_populate_interface_from_header(erf_t *erf_priv, wtap *wth, union wtap_pseudo_header *pseudo_header)
1042 {
1043   guint64 host_id;
1044   guint8 source_id;
1045   guint8 if_num;
1046
1047   if (!pseudo_header)
1048     return -1;
1049
1050   if_num = pseudo_header->erf.phdr.flags & 0x03;
1051
1052   erf_get_source_from_header(pseudo_header, &host_id, &source_id);
1053
1054   return erf_populate_interface(erf_priv, wth, pseudo_header, host_id, source_id, if_num);
1055 }
1056
1057 static struct erf_if_mapping* erf_find_interface_mapping(erf_t *erf_priv, guint64 host_id, guint8 source_id)
1058 {
1059   struct erf_if_mapping if_map_lookup;
1060
1061   if (!erf_priv)
1062     return NULL;
1063
1064   if_map_lookup.host_id = host_id;
1065   if_map_lookup.source_id = source_id;
1066
1067   return (struct erf_if_mapping*) g_hash_table_lookup(erf_priv->if_map, &if_map_lookup);
1068 }
1069
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)
1071 {
1072   /* Source XXX,*/
1073   char sourceid_buf[16];
1074   /* Host XXXXXXXXXXXX,*/
1075   char hostid_buf[24];
1076
1077   sourceid_buf[0] = '\0';
1078   hostid_buf[0] = '\0';
1079
1080   if (host_id > 0) {
1081     g_snprintf(hostid_buf, sizeof(hostid_buf), " Host %012" G_GINT64_MODIFIER "x,", host_id);
1082   }
1083
1084   if (source_id > 0) {
1085     g_snprintf(sourceid_buf, sizeof(sourceid_buf), " Source %u,", source_id);
1086   }
1087
1088   if (descr) {
1089     wtap_optionblock_set_option_string_format(block, option_id, "%s (ERF%s%s Interface %d)", descr, hostid_buf, sourceid_buf, if_num);
1090   } else {
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);
1092   }
1093 }
1094
1095 static int erf_update_implicit_host_id(erf_t *erf_priv, wtap *wth, guint64 implicit_host_id)
1096 {
1097   GHashTableIter iter;
1098   gpointer iter_value;
1099   GList* implicit_list = NULL;
1100   GList* item = NULL;
1101   wtap_optionblock_t int_data;
1102   struct erf_if_mapping* if_map = NULL;
1103   int i;
1104
1105   if (!erf_priv)
1106     return -1;
1107
1108   erf_priv->implicit_host_id = implicit_host_id;
1109
1110   /*
1111    * We need to update the descriptions of all the interfaces with no Host
1112    * ID to the correct Host ID.
1113    */
1114   g_hash_table_iter_init(&iter, erf_priv->if_map);
1115
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);
1123     }
1124   }
1125
1126   if (implicit_list) {
1127     item = implicit_list;
1128     do {
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);
1136         }
1137       }
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)));
1143
1144     g_list_free(implicit_list);
1145   }
1146
1147   return 0;
1148 }
1149
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)
1151 {
1152   wtap_optionblock_t int_data;
1153   wtapng_if_descr_mandatory_t* int_data_mand;
1154   struct erf_if_mapping* if_map = NULL;
1155
1156   if (!wth || !pseudo_header || !erf_priv || if_num > 3)
1157     return -1;
1158
1159   if ((pseudo_header->erf.phdr.type & 0x7f) == ERF_TYPE_META) {
1160     /*
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
1164      * Implicit Host ID.
1165      */
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);
1168     }
1169   }
1170
1171   if (host_id == 0) {
1172     host_id = erf_priv->implicit_host_id;
1173   }
1174
1175   if_map = erf_find_interface_mapping(erf_priv, host_id, source_id);
1176
1177   if (!if_map) {
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);
1181
1182   }
1183
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;
1187   }
1188
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);
1191
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 */
1197
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;
1210
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);
1213
1214   if_map->interfaces[if_num].if_index = (int) wth->interface_data->len;
1215   g_array_append_val(wth->interface_data, int_data);
1216
1217   return if_map->interfaces[if_num].if_index;
1218 }
1219
1220 static guint32 erf_meta_read_tag(struct erf_meta_tag* tag, guint8 *tag_ptr, guint32 remaining_len)
1221 {
1222   guint16 tagtype;
1223   guint16 taglength;
1224   guint32 tagtotallength;
1225
1226   if (!tag_ptr || !tag || remaining_len < ERF_META_TAG_HEADERLEN)
1227     return 0;
1228
1229   /* tagtype (2 bytes) */
1230   tagtype = pntoh16(&tag_ptr[0]);
1231
1232   /* length (2 bytes) */
1233   taglength = pntoh16(&tag_ptr[2]);
1234
1235   tagtotallength = ERF_META_TAG_ALIGNED_LENGTH(taglength);
1236
1237   if (remaining_len < tagtotallength) {
1238     return 0;
1239   }
1240
1241   tag->type = tagtype;
1242   tag->length = taglength;
1243   tag->value = &tag_ptr[4];
1244
1245   return tagtotallength;
1246 }
1247
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)
1249 {
1250   struct erf_meta_tag tag = {0, 0, NULL};
1251
1252   wtap_optionblock_t shb_hdr;
1253   char* tmp;
1254   gchar* app_name    = NULL;
1255   gchar* app_version = NULL;
1256   gchar* model       = NULL;
1257   gchar* descr       = NULL;
1258   gchar* cpu         = NULL;
1259   gchar* modelcpu    = NULL;
1260   guint32 tagtotallength;
1261
1262   if (!wth || !state || !wth->shb_hdr)
1263     return -1;
1264
1265   /* XXX: wth->shb_hdr is already created by different layer, using directly for now. */
1266   shb_hdr = wth->shb_hdr;
1267
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:
1271       {
1272         if (erf_priv->capture_metadata == TRUE) {
1273           return 0;
1274         }
1275
1276         switch (tag.type) {
1277           case ERF_META_TAG_comment:
1278             wtap_optionblock_set_option_string(shb_hdr, OPT_COMMENT, tag.value, tag.length);
1279             break;
1280         }
1281         /* Fall through */
1282       }
1283       case ERF_META_SECTION_HOST:
1284       {
1285         if (erf_priv->host_metadata == TRUE) {
1286           return 0;
1287         }
1288
1289         switch (tag.type) {
1290           case ERF_META_TAG_model:
1291             g_free(model);
1292             model = g_strndup((gchar*) tag.value, tag.length);
1293             break;
1294           case ERF_META_TAG_cpu:
1295             g_free(cpu);
1296             cpu = g_strndup((gchar*) tag.value, tag.length);
1297             break;
1298           case ERF_META_TAG_descr:
1299             g_free(descr);
1300             descr = g_strndup((gchar*) tag.value, tag.length);
1301             break;
1302           case ERF_META_TAG_os:
1303             wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_OS, tag.value, tag.length);
1304             break;
1305           case ERF_META_TAG_app_name:
1306             g_free(app_name);
1307             app_name = g_strndup((gchar*) tag.value, tag.length);
1308             break;
1309           case ERF_META_TAG_app_version:
1310             g_free(app_version);
1311             app_version = g_strndup((gchar*) tag.value, tag.length);
1312             break;
1313             /* TODO: dag_version? */
1314             /* TODO: could concatenate comment(s)? */
1315           default:
1316             break;
1317         }
1318       }
1319       break;
1320     }
1321
1322     state->tag_ptr += tagtotallength;
1323     state->remaining_len -= tagtotallength;
1324   }
1325
1326   /* Post processing */
1327
1328   if (app_name) {
1329     /* If no app_version will just use app_name */
1330
1331     tmp = g_strjoin(" ", app_name, app_version, NULL);
1332     wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_USERAPPL, tmp, strlen(tmp));
1333     g_free(tmp);
1334
1335     g_free(app_name);
1336     g_free(app_version);
1337     app_name = NULL;
1338     app_version = NULL;
1339   }
1340
1341   /* For the hardware field show description followed by (model; cpu) */
1342   /* Build "Model; CPU" part */
1343   if (model || cpu) {
1344     /* g_strjoin() would be nice to use here if the API didn't stop on the first NULL... */
1345     if (model && cpu) {
1346       modelcpu = g_strconcat(model, "; ", cpu, NULL);
1347     } else if (cpu) {
1348       modelcpu = cpu;
1349       /* avoid double-free */
1350       cpu = NULL;
1351     } else {
1352       modelcpu = model;
1353       /* avoid double-free */
1354       model = NULL;
1355     }
1356   }
1357
1358   /* Combine into "Description (Model; CPU)" */
1359   if (state->sectiontype == ERF_META_SECTION_HOST && descr) {
1360     if (modelcpu) {
1361       wtap_optionblock_set_option_string_format(shb_hdr, OPT_SHB_HARDWARE, "%s (%s)", descr, modelcpu);
1362     } else {
1363       wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_HARDWARE, descr, strlen(descr));
1364       /*descr = NULL;*/
1365     }
1366   } else if (modelcpu) {
1367     wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_HARDWARE, modelcpu, strlen(modelcpu));
1368     /*modelcpu = NULL;*/
1369   }
1370
1371   /* Free the fields we didn't end up using */
1372   g_free(modelcpu);
1373   g_free(model);
1374   g_free(descr);
1375   g_free(cpu);
1376
1377   if (state->sectiontype == ERF_META_SECTION_CAPTURE) {
1378     erf_priv->capture_metadata = TRUE;
1379   } else {
1380     erf_priv->host_metadata = TRUE;
1381   }
1382
1383   return 1;
1384 }
1385
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)
1387 {
1388   struct erf_meta_tag tag = {0, 0, NULL};
1389
1390   guint32 tagtotallength;
1391
1392   if (!wth || !state)
1393     return -1;
1394
1395   if (state->if_map->module_metadata == TRUE) {
1396     return 0;
1397   }
1398
1399   while ((tagtotallength = erf_meta_read_tag(&tag, state->tag_ptr, state->remaining_len)) && !ERF_META_IS_SECTION(tag.type)) {
1400       switch (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);
1404           }
1405           break;
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);
1410           }
1411           break;
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);
1415           break;
1416       }
1417
1418     state->tag_ptr += tagtotallength;
1419     state->remaining_len -= tagtotallength;
1420   }
1421
1422   state->if_map->module_metadata = TRUE;
1423
1424   return 1;
1425 }
1426
1427 static int populate_interface_info(erf_t *erf_priv, wtap *wth, union wtap_pseudo_header *pseudo_header, struct erf_meta_read_state *state)
1428 {
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;
1435   guint32 if_num = 0;
1436   struct erf_if_info* if_info = NULL;
1437
1438   memset(&if_filter, 0, sizeof(if_filter));
1439
1440   if (!wth || !state || !pseudo_header || !state->if_map)
1441     return -1;
1442
1443   /* Section ID of interface is defined to match ERF interface id. */
1444   if_num = state->sectionid - 1;
1445   /*
1446    * Get or create the interface (there can be multiple interfaces in
1447    * a MetaERF record).
1448    */
1449   if (if_num < 4) { /* Note: -1u > 4*/
1450     if_info = &state->if_map->interfaces[if_num];
1451     interface_index = if_info->if_index;
1452
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;
1457
1458       /* First iterate tags, checking we aren't looking at a timing port */
1459       /*
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.
1463        */
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? */
1469
1470             if_info->if_index = -2;
1471             interface_index = -2;
1472           }
1473         } else if (tag.type == ERF_META_TAG_stream_num) {
1474           if (tag.length >= 4) {
1475             if_info->stream_num = (gint32) pntoh32(tag.value);
1476           }
1477         }
1478
1479         tag_ptr_tmp += tagtotallength;
1480         remaining_len_tmp -= tagtotallength;
1481       }
1482
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);
1486       }
1487     }
1488
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 */
1495       return 0;
1496     } else {
1497       return -1;
1498     }
1499   }
1500
1501   /*
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.
1505    */
1506   if (!int_data || state->if_map->interface_metadata & (1 << if_num))
1507     return 0;
1508
1509   while ((tagtotallength = erf_meta_read_tag(&tag, state->tag_ptr, state->remaining_len)) && !ERF_META_IS_SECTION(tag.type)) {
1510     switch (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);
1516
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);
1520           }
1521         }
1522         break;
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);
1527
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);
1531           }
1532         }
1533         break;
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));
1537         break;
1538       case ERF_META_TAG_if_num:
1539         /*
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.
1543          */
1544         /* TODO: might want to put this number in description */
1545         break;
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;
1550         }
1551         break;
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;
1557         }
1558         break;
1559       case ERF_META_TAG_comment:
1560         wtap_optionblock_set_option_string(int_data, OPT_COMMENT, tag.value, tag.length);
1561         break;
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;
1566         break;
1567       default:
1568         break;
1569     }
1570
1571     state->tag_ptr += tagtotallength;
1572     state->remaining_len -= tagtotallength;
1573   }
1574
1575   /* Post processing */
1576   /*
1577    * XXX: Assumes module defined first. It is higher in hierarchy so only set
1578    * if not already.
1579    */
1580
1581   /*
1582    * XXX: Missing exposed existence/type-check. No way currently to check if
1583    * been set in the optionblock.
1584    */
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);
1589     /*
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.
1592      */
1593   }
1594
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;
1598   }
1599
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;
1603   }
1604
1605   state->interface_metadata |= 1 << if_num;
1606
1607   return 1;
1608 }
1609
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)
1611 {
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;
1618   guint32 if_num = 0;
1619   gint32 stream_num = -1;
1620   guint8 *tag_ptr_tmp;
1621   guint32 remaining_len_tmp;
1622   struct erf_if_info* if_info = NULL;
1623
1624   memset(&if_filter, 0, sizeof(if_filter));
1625
1626   if (!wth || !pseudo_header || !state || !state->if_map)
1627     return -1;
1628
1629   tag_ptr_tmp = state->tag_ptr;
1630   remaining_len_tmp = state->remaining_len;
1631
1632   /*
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.
1637    */
1638
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;
1642   } else {
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);
1648         }
1649       }
1650
1651       tag_ptr_tmp += tagtotallength;
1652       remaining_len_tmp -= tagtotallength;
1653     }
1654   }
1655   /* Otherwise assume the stream applies to all interfaces in the record */
1656
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];
1661
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))) {
1666       continue;
1667     }
1668
1669     if (if_info->stream_num != -1
1670         && if_info->stream_num != stream_num) {
1671       continue;
1672     }
1673
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);
1679     }
1680
1681     if (!int_data) {
1682       continue;
1683     }
1684
1685     while ((tagtotallength = erf_meta_read_tag(&tag, tag_ptr_tmp, remaining_len_tmp)) && !ERF_META_IS_SECTION(tag.type)) {
1686       switch (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;
1692
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;
1697             }
1698           }
1699           break;
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);
1704
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;
1708             }
1709           }
1710           break;
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;
1717           }
1718           break;
1719         default:
1720           break;
1721       }
1722
1723       tag_ptr_tmp += tagtotallength;
1724       remaining_len_tmp -= tagtotallength;
1725     }
1726   }
1727   state->tag_ptr = tag_ptr_tmp;
1728   state->remaining_len = remaining_len_tmp;
1729
1730   return 1;
1731 }
1732
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)
1735 {
1736   struct erf_meta_read_state state;
1737   struct erf_meta_read_state *state_post = NULL;
1738   guint64 host_id;
1739   guint8 source_id;
1740   GList *post_list = NULL;
1741   GList *item = NULL;
1742
1743   struct erf_meta_tag tag = {0, 0, NULL};
1744   guint32 tagtotallength;
1745
1746   if (!erf_priv || !wth || !pseudo_header)
1747     return -1;
1748
1749   memset(&state, 0, sizeof(struct erf_meta_read_state));
1750
1751   erf_get_source_from_header(pseudo_header, &host_id, &source_id);
1752
1753   if (host_id == 0) {
1754     host_id = erf_priv->implicit_host_id;
1755   }
1756
1757   state.if_map = erf_find_interface_mapping(erf_priv, host_id, source_id);
1758
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);
1763
1764   }
1765
1766   /*
1767    * Skip the record if we already have enough metadata (seen one section for
1768    * each type for the source).
1769    */
1770   if ((state.if_map->interface_metadata & 0x03)
1771       && erf_priv->host_metadata && erf_priv->capture_metadata) {
1772     return 0;
1773   }
1774
1775   state.tag_ptr = wth->frame_buffer->data;
1776   state.remaining_len = packet_size;
1777
1778   /* Read until see next section tag */
1779   while ((tagtotallength = erf_meta_read_tag(&tag, state.tag_ptr, state.remaining_len))) {
1780     /*
1781      * Skip until we get to the next section tag (which could be the current tag
1782      * after an empty section or successful parsing).
1783      */
1784     if (!ERF_META_IS_SECTION(tag.type)) {
1785       /* adjust offset */
1786       state.tag_ptr += tagtotallength;
1787       state.remaining_len -= tagtotallength;
1788       continue;
1789     }
1790
1791     /*
1792      * We are now looking at the next section (and would have exited the loop
1793      * if we reached the end).
1794      */
1795
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)) {
1800         /* do nothing */
1801       } else {
1802         state.parentsectiontype = state.sectiontype;
1803         state.parentsectionid = state.sectionid;
1804       }
1805     }
1806
1807     /* Update with new sectiontype */
1808     state.sectiontype = tag.type;
1809     if (tag.length >= 4) {
1810       state.sectionid = pntoh16(tag.value);
1811     } else {
1812       state.sectionid = 0;
1813     }
1814
1815     /* Adjust offset to that of first tag in section */
1816     state.tag_ptr += tagtotallength;
1817     state.remaining_len -= tagtotallength;
1818
1819     if ((tagtotallength = erf_meta_read_tag(&tag, state.tag_ptr, state.remaining_len))) {
1820       /*
1821        * Process parent section tag if present (which must be the first tag in
1822        * the section).
1823        */
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]);
1827       }
1828     }
1829
1830     /* Skip empty sections (includes if above read fails) */
1831     if (ERF_META_IS_SECTION(tag.type)) {
1832       continue;
1833     }
1834
1835     /*
1836      * Skip sections that don't apply to the general set of records
1837      * (extension point for per-packet/event metadata).
1838      */
1839     if (state.sectionid & 0x8000) {
1840       continue;
1841     }
1842
1843     /*
1844      * Start at first tag in section, makes loop
1845      * simpler in called functions too. Also makes iterating after failure
1846      * much simpler.
1847      */
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);
1853         break;
1854       case ERF_META_SECTION_MODULE:
1855         populate_module_info(erf_priv, wth, pseudo_header, &state);
1856         break;
1857       case ERF_META_SECTION_INTERFACE:
1858         populate_interface_info(erf_priv, wth, pseudo_header, &state);
1859         break;
1860       case ERF_META_SECTION_STREAM:
1861         /*
1862          * XXX: Treat streams specially in case the stream information appears
1863          * before the interface information, as we associate them to interface
1864          * data.
1865          */
1866         post_list = g_list_append(post_list, g_memdup(&state, sizeof(struct erf_meta_read_state)));
1867         break;
1868       case ERF_META_SECTION_SOURCE:
1869       case ERF_META_SECTION_DNS:
1870       default:
1871         /* TODO: Not yet implemented */
1872         break;
1873     }
1874   }
1875
1876   /* Process streams last */
1877   if (post_list) {
1878     item = post_list;
1879     do {
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);
1884           break;
1885       }
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);
1890   }
1891
1892   /*
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.
1895    */
1896   state.if_map->interface_metadata |= state.interface_metadata;
1897
1898   return 0;
1899 }
1900
1901 static void erf_close(wtap *wth)
1902 {
1903   erf_t* erf_priv = (erf_t*)wth->priv;
1904
1905   erf_priv_free(erf_priv);
1906   /* XXX: Prevent double free by wtap_close() */
1907   wth->priv = NULL;
1908 }
1909
1910 /*
1911  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1912  *
1913  * Local Variables:
1914  * c-basic-offset: 2
1915  * tab-width: 8
1916  * indent-tabs-mode: nil
1917  * End:
1918  *
1919  * vi: set shiftwidth=2 tabstop=8 expandtab:
1920  * :indentSize=2:tabSize=8:noTabs=true:
1921  */