diff --git a/cfile.c b/cfile.c index a689b2e11c..830e871593 100644 --- a/cfile.c +++ b/cfile.c @@ -29,8 +29,8 @@ #include "cfile.h" -const char * -cap_file_get_interface_name(void *data, guint32 interface_id) +static const wtapng_if_descr_t * +cap_file_get_interface_desc(void *data, guint32 interface_id) { capture_file *cf = (capture_file *) data; wtapng_iface_descriptions_t *idb_info; @@ -42,6 +42,13 @@ cap_file_get_interface_name(void *data, guint32 interface_id) wtapng_if_descr = &g_array_index(idb_info->interface_data, wtapng_if_descr_t, interface_id); g_free(idb_info); + return wtapng_if_descr; +} + +const char * +cap_file_get_interface_name(void *data, guint32 interface_id) +{ + const wtapng_if_descr_t *wtapng_if_descr = cap_file_get_interface_desc(data, interface_id); if (wtapng_if_descr) { if (wtapng_if_descr->if_name) @@ -52,6 +59,18 @@ cap_file_get_interface_name(void *data, guint32 interface_id) return "unknown"; } +const GArray * +cap_file_get_interface_option(void *data, guint32 interface_id, guint16 option_code) +{ + const wtapng_if_descr_t *wtapng_if_descr = cap_file_get_interface_desc(data, interface_id); + + if (wtapng_if_descr && wtapng_if_descr->if_options) { + gint code = (gint) option_code; + return (const GArray *) g_hash_table_lookup(wtapng_if_descr->if_options, &code); + } + return NULL; +} + void cap_file_init(capture_file *cf) { diff --git a/cfile.h b/cfile.h index f34c34ee14..f164303f18 100644 --- a/cfile.h +++ b/cfile.h @@ -133,6 +133,8 @@ extern void cap_file_init(capture_file *cf); extern const char *cap_file_get_interface_name(void *data, guint32 interface_id); +extern const GArray *cap_file_get_interface_option(void *data, guint32 interface_id, guint16 option_code); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/epan/epan-int.h b/epan/epan-int.h index 35e91975be..5089025c30 100644 --- a/epan/epan-int.h +++ b/epan/epan-int.h @@ -31,6 +31,8 @@ struct epan_session { const nstime_t *(*get_frame_ts)(void *data, guint32 frame_num); const char *(*get_interface_name)(void *data, guint32 interface_id); const char *(*get_user_comment)(void *data, const frame_data *fd); + const GArray *(*get_interface_option)(void *data, guint32 interface_id, + guint16 option_code); }; #endif diff --git a/epan/epan.c b/epan/epan.c index e83864121d..4426981b2f 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -178,6 +178,15 @@ epan_get_interface_name(const epan_t *session, guint32 interface_id) return NULL; } +const GArray * +epan_get_interface_option(const epan_t *session, guint32 interface_id, guint16 option_code) +{ + if (session->get_interface_option) + return session->get_interface_option(session->data, interface_id, option_code); + + return NULL; +} + const nstime_t * epan_get_frame_ts(const epan_t *session, guint32 frame_num) { diff --git a/epan/epan.h b/epan/epan.h index faf8e3a448..da00026bb7 100644 --- a/epan/epan.h +++ b/epan/epan.h @@ -18,7 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #ifndef __EPAN_H__ #define __EPAN_H__ @@ -124,7 +123,7 @@ void epan_circuit_cleanup(void); /** A client will create one epan_t for an entire dissection session. * A single epan_t will be used to analyze the entire sequence of packets, * sequentially, in a single session. A session corresponds to a single - * packet trace file. The reaons epan_t exists is that some packets in + * packet trace file. The reason epan_t exists is that some packets in * some protocols cannot be decoded without knowledge of previous packets. * This inter-packet "state" is stored in the epan_t. */ @@ -136,6 +135,8 @@ const char *epan_get_user_comment(const epan_t *session, const frame_data *fd); const char *epan_get_interface_name(const epan_t *session, guint32 interface_id); +const GArray *epan_get_interface_option(const epan_t *session, guint32 interface_id, guint16 option_code); + const nstime_t *epan_get_frame_ts(const epan_t *session, guint32 frame_num); WS_DLL_PUBLIC void epan_free(epan_t *session); diff --git a/file.c b/file.c index d57e0a9b8b..2eaecf5cc0 100644 --- a/file.c +++ b/file.c @@ -329,6 +329,7 @@ ws_epan_new(capture_file *cf) epan->get_frame_ts = ws_get_frame_ts; epan->get_interface_name = cap_file_get_interface_name; epan->get_user_comment = ws_get_user_comment; + epan->get_interface_option = cap_file_get_interface_option; return epan; } diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index c350532b3f..875571866d 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -344,6 +344,9 @@ typedef struct wtapng_block_s { wtapng_if_stats_t if_stats; } data; + /* keys are (pointers to) gint, vals are (pointers to) arrays of GByteArray */ + GHashTable * pcapng_options; + /* * XXX - currently don't know how to handle these! * @@ -357,6 +360,69 @@ typedef struct wtapng_block_s { int *file_encap; } wtapng_block_t; +static void +pcapng_destroy_option_key(gpointer data) +{ + g_free(data); +} + +static void +pcapng_destroy_option_value(gpointer data) +{ + GArray * pval = (GArray *) data; + if (pval) { + guint i; + for(i=0; ilen; i++) { + GByteArray * element = g_array_index(pval, GByteArray *, i); + g_byte_array_unref(element); + } + g_array_unref(pval); + } +} + +static void +pcapng_init_block_options(wtapng_block_t *wblock) +{ + wblock->pcapng_options = g_hash_table_new_full(g_int_hash, + g_int_equal, + pcapng_destroy_option_key, + pcapng_destroy_option_value); +} + +static void +pcapng_unref_block_options(wtapng_block_t *wblock) +{ + if (wblock->pcapng_options) { + g_hash_table_destroy(wblock->pcapng_options); + wblock->pcapng_options = NULL; + } +} + +static void +pcapng_collect_block_option(wtapng_block_t *wblock, guint16 code, + const guint8 *data, gsize len) +{ + if (wblock->pcapng_options) { + gint tempkey = (gint) code; + GArray * pval = (GArray *) g_hash_table_lookup(wblock->pcapng_options, &tempkey); + if(!pval) { + /* this key does not yet exist, so create a + new key and new array for its first value, + and insert it into the hash table */ + gpointer pkey = g_try_malloc(sizeof(gint)); + if (pkey) { + pval = g_array_new(FALSE, TRUE, sizeof(GByteArray *)); + g_hash_table_insert(wblock->pcapng_options, pkey, pval); + } + } + if (pval) { + GByteArray * optionbuf = g_byte_array_new_take(g_strndup(data, len), len); + g_array_append_val(pval, optionbuf); + } + } +} + + /* Interface data in private struct */ typedef struct interface_data_s { int wtap_encap; @@ -607,6 +673,11 @@ pcapng_read_section_header_block(FILE_T fh, gboolean first_block, block_read += bytes_read; to_read -= bytes_read; + if (oh.option_code) { + /* collect the raw option information */ + pcapng_collect_block_option(wblock, oh.option_code, option_content, oh.option_length); + } + /* handle option content */ switch (oh.option_code) { case(OPT_EOFOPT): @@ -779,6 +850,11 @@ pcapng_read_if_descr_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, block_read += bytes_read; to_read -= bytes_read; + if (oh.option_code) { + /* collect the raw option information */ + pcapng_collect_block_option(wblock, oh.option_code, option_content, oh.option_length); + } + /* handle option content */ switch (oh.option_code) { case(0): /* opt_endofopt */ @@ -1206,6 +1282,11 @@ pcapng_read_packet_block(FILE_T fh, pcapng_block_header_t *bh, pcapng_t *pn, wta block_read += bytes_read; to_read -= bytes_read; + if (oh.option_code) { + /* collect the raw option information */ + pcapng_collect_block_option(wblock, oh.option_code, option_content, oh.option_length); + } + /* handle option content */ switch (oh.option_code) { case(OPT_EOFOPT): @@ -1827,6 +1908,11 @@ pcapng_read_interface_statistics_block(FILE_T fh, pcapng_block_header_t *bh, pca block_read += bytes_read; to_read -= bytes_read; + if (oh.option_code) { + /* collect the raw option information */ + pcapng_collect_block_option(wblock, oh.option_code, option_content, oh.option_length); + } + /* handle option content */ switch (oh.option_code) { case(0): /* opt_endofopt */ @@ -2131,6 +2217,9 @@ pcapng_process_idb(wtap *wth, pcapng_t *pcapng, wtapng_block_t *wblock) /* Interface statistics */ int_data.num_stat_entries = 0; int_data.interface_statistics = NULL; + /* move the options over */ + int_data.if_options = wblock->pcapng_options; + wblock->pcapng_options = NULL; g_array_append_val(wth->interface_data, int_data); wth->number_of_interfaces++; @@ -2154,6 +2243,8 @@ pcapng_open(wtap *wth, int *err, gchar **err_info) pcapng_block_header_t bh; gint64 saved_offset; + pcapng_init_block_options(&wblock); + pn.shb_read = FALSE; /* we don't know the byte swapping of the file yet */ pn.byte_swapped = FALSE; @@ -2174,6 +2265,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info) bytes_read = pcapng_read_block(wth->fh, TRUE, &pn, &wblock, err, err_info); if (bytes_read <= 0) { pcapng_debug0("pcapng_open: couldn't read first SHB"); + pcapng_unref_block_options(&wblock); *err = file_error(wth->fh, err_info); if (*err != 0 && *err != WTAP_ERR_SHORT_READ) return -1; @@ -2188,6 +2280,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info) * binary data? */ pcapng_debug1("pcapng_open: first block type %u not SHB", wblock.type); + pcapng_unref_block_options(&wblock); return 0; } pn.shb_read = TRUE; @@ -2233,6 +2326,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info) if (bytes_read != sizeof bh) { *err = file_error(wth->fh, err_info); pcapng_debug3("pcapng_open: Check for more IDB:s, file_read() returned %d instead of %u, err = %d.", bytes_read, (unsigned int)sizeof bh, *err); + pcapng_unref_block_options(&wblock); if (*err == 0) *err = WTAP_ERR_SHORT_READ; return -1; @@ -2258,6 +2352,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info) if (bytes_read <= 0) { pcapng_debug0("pcapng_open: couldn't read IDB"); *err = file_error(wth->fh, err_info); + pcapng_unref_block_options(&wblock); if (*err == 0) *err = WTAP_ERR_SHORT_READ; return -1; @@ -2265,6 +2360,7 @@ pcapng_open(wtap *wth, int *err, gchar **err_info) pcapng_process_idb(wth, pcapng, &wblock); pcapng_debug2("pcapng_open: Read IDB number_of_interfaces %u, wtap_encap %i", wth->number_of_interfaces, *wblock.file_encap); } + pcapng_unref_block_options(&wblock); return 1; } @@ -2279,6 +2375,8 @@ pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset) wtapng_if_descr_t *wtapng_if_descr; wtapng_if_stats_t if_stats; + pcapng_init_block_options(&wblock); + *data_offset = file_tell(wth->fh); pcapng_debug1("pcapng_read: data_offset is initially %" G_GINT64_MODIFIER "d", *data_offset); @@ -2295,6 +2393,7 @@ pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset) if (bytes_read <= 0) { pcapng_debug1("pcapng_read: data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset); pcapng_debug0("pcapng_read: couldn't read packet block"); + pcapng_unref_block_options(&wblock); return FALSE; } @@ -2305,6 +2404,7 @@ pcapng_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset) wth->phdr.pkt_encap = WTAP_ENCAP_UNKNOWN; *err = WTAP_ERR_UNSUPPORTED; *err_info = g_strdup_printf("pcapng: multi-section files not currently supported"); + pcapng_unref_block_options(&wblock); return FALSE; case(BLOCK_TYPE_PB): @@ -2373,6 +2473,7 @@ got_packet: /*pcapng_debug2("Read length: %u Packet length: %u", bytes_read, wth->phdr.caplen);*/ pcapng_debug1("pcapng_read: data_offset is finally %" G_GINT64_MODIFIER "d", *data_offset + bytes_read); + pcapng_unref_block_options(&wblock); return TRUE; } @@ -2389,10 +2490,12 @@ pcapng_seek_read(wtap *wth, gint64 seek_off, int bytes_read; wtapng_block_t wblock; + pcapng_init_block_options(&wblock); /* seek to the right file position */ bytes_read64 = file_seek(wth->random_fh, seek_off, SEEK_SET, err); if (bytes_read64 <= 0) { + pcapng_unref_block_options(&wblock); return FALSE; /* Seek error */ } pcapng_debug1("pcapng_seek_read: reading at offset %" G_GINT64_MODIFIER "u", seek_off); @@ -2406,6 +2509,7 @@ pcapng_seek_read(wtap *wth, gint64 seek_off, if (bytes_read <= 0) { pcapng_debug3("pcapng_seek_read: couldn't read packet block (err=%d, errno=%d, bytes_read=%d).", *err, errno, bytes_read); + pcapng_unref_block_options(&wblock); return FALSE; } @@ -2414,9 +2518,11 @@ pcapng_seek_read(wtap *wth, gint64 seek_off, if (wblock.type != BLOCK_TYPE_PB && wblock.type != BLOCK_TYPE_EPB && wblock.type != BLOCK_TYPE_SPB) { pcapng_debug1("pcapng_seek_read: block type %u not PB/EPB/SPB", wblock.type); + pcapng_unref_block_options(&wblock); return FALSE; } + pcapng_unref_block_options(&wblock); return TRUE; } diff --git a/wiretap/wtap.c b/wiretap/wtap.c index 8774f35e1f..d8bbdbb65f 100644 --- a/wiretap/wtap.c +++ b/wiretap/wtap.c @@ -925,6 +925,9 @@ wtap_close(wtap *wth) if(wtapng_if_descr->num_stat_entries != 0){ g_array_free(wtapng_if_descr->interface_statistics, TRUE); } + if(wtapng_if_descr->if_options){ + g_hash_table_destroy(wtapng_if_descr->if_options); + } } if(wth->number_of_interfaces != 0){ g_array_free(wth->interface_data, TRUE); diff --git a/wiretap/wtap.h b/wiretap/wtap.h index db18a2f3af..bd6e6e8b42 100644 --- a/wiretap/wtap.h +++ b/wiretap/wtap.h @@ -1118,6 +1118,7 @@ typedef struct wtapng_if_descr_s { guint8 num_stat_entries; GArray *interface_statistics; /**< An array holding the interface statistics from * pcapng ISB:s or equivalent(?)*/ + GHashTable *if_options; } wtapng_if_descr_t;