diff --git a/wiretap/pcapng.c b/wiretap/pcapng.c index 0d070c6b12..8729177b0b 100644 --- a/wiretap/pcapng.c +++ b/wiretap/pcapng.c @@ -56,15 +56,6 @@ pcapng_seek_read(wtap *wth, gint64 seek_off, static void pcapng_close(wtap *wth); - -/* pcapng: common block header file encoding for every block type */ -typedef struct pcapng_block_header_s { - guint32 block_type; - guint32 block_total_length; - /* x bytes block_body */ - /* guint32 block_total_length */ -} pcapng_block_header_t; - /* * Minimum block size = size of block header + size of block trailer. */ @@ -82,34 +73,11 @@ typedef struct pcapng_block_header_s { */ #define MAX_BLOCK_SIZE (16*1024*1024) -/* pcapng: section header block file encoding */ -typedef struct pcapng_section_header_block_s { - /* pcapng_block_header_t */ - guint32 magic; - guint16 version_major; - guint16 version_minor; - guint64 section_length; /* might be -1 for unknown */ - /* ... Options ... */ -} pcapng_section_header_block_t; - /* * Minimum SHB size = minimum block size + size of fixed length portion of SHB. */ #define MIN_SHB_SIZE ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_section_header_block_t))) -/* pcapng: interface description block file encoding */ -typedef struct pcapng_interface_description_block_s { - guint16 linktype; - guint16 reserved; - guint32 snaplen; - /* ... Options ... */ -} pcapng_interface_description_block_t; - -/* - * Minimum IDB size = minimum block size + size of fixed length portion of IDB. - */ -#define MIN_IDB_SIZE ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_interface_description_block_t))) - /* pcapng: packet block file encoding (obsolete) */ typedef struct pcapng_packet_block_s { guint16 interface_id; @@ -170,14 +138,6 @@ typedef struct pcapng_name_resolution_block_s { */ #define MIN_NRB_SIZE ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_name_resolution_block_t))) -/* pcapng: interface statistics block file encoding */ -typedef struct pcapng_interface_statistics_block_s { - guint32 interface_id; - guint32 timestamp_high; - guint32 timestamp_low; - /* ... Options ... */ -} pcapng_interface_statistics_block_t; - /* * Minimum ISB size = minimum block size + size of fixed length portion of ISB. */ @@ -2739,85 +2699,25 @@ pcapng_write_section_header_block(wtap_dumper *wdh, int *err) { pcapng_block_header_t bh; pcapng_section_header_block_t shb; - const guint32 zero_pad = 0; - gboolean have_options = FALSE; - struct option option_hdr; /* guint16 type, guint16 value_length; */ - guint32 options_total_length = 0; - guint32 comment_len = 0, shb_hardware_len = 0, shb_os_len = 0, shb_user_appl_len = 0; - guint32 comment_pad_len = 0, shb_hardware_pad_len = 0, shb_os_pad_len = 0, shb_user_appl_pad_len = 0; - char *opt_comment, *shb_hardware, *shb_os, *shb_user_appl; if (wdh->shb_hdr) { pcapng_debug("pcapng_write_section_header_block: Have shb_hdr"); - /* Check if we should write comment option */ - wtap_optionblock_get_option_string(wdh->shb_hdr, OPT_COMMENT, &opt_comment); - if (opt_comment) { - have_options = TRUE; - comment_len = (guint32)strlen(opt_comment) & 0xffff; - if ((comment_len % 4)) { - comment_pad_len = 4 - (comment_len % 4); - } else { - comment_pad_len = 0; - } - options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ; - } - /* Check if we should write shb_hardware option */ - wtap_optionblock_get_option_string(wdh->shb_hdr, OPT_SHB_HARDWARE, &shb_hardware); - if (shb_hardware) { - have_options = TRUE; - shb_hardware_len = (guint32)strlen(shb_hardware) & 0xffff; - if ((shb_hardware_len % 4)) { - shb_hardware_pad_len = 4 - (shb_hardware_len % 4); - } else { - shb_hardware_pad_len = 0; - } - options_total_length = options_total_length + shb_hardware_len + shb_hardware_pad_len + 4 /* options tag */ ; - } - - /* Check if we should write shb_os option */ - wtap_optionblock_get_option_string(wdh->shb_hdr, OPT_SHB_OS, &shb_os); - if (shb_os) { - have_options = TRUE; - shb_os_len = (guint32)strlen(shb_os) & 0xffff; - if ((shb_os_len % 4)) { - shb_os_pad_len = 4 - (shb_os_len % 4); - } else { - shb_os_pad_len = 0; - } - options_total_length = options_total_length + shb_os_len + shb_os_pad_len + 4 /* options tag */ ; - } - - /* Check if we should write shb_user_appl option */ - wtap_optionblock_get_option_string(wdh->shb_hdr, OPT_SHB_USERAPPL, &shb_user_appl); - if (shb_user_appl) { - have_options = TRUE; - shb_user_appl_len = (guint32)strlen(shb_user_appl) & 0xffff; - if ((shb_user_appl_len % 4)) { - shb_user_appl_pad_len = 4 - (shb_user_appl_len % 4); - } else { - shb_user_appl_pad_len = 0; - } - options_total_length = options_total_length + shb_user_appl_len + shb_user_appl_pad_len + 4 /* options tag */ ; - } - - if (have_options) { - /* End-of-options tag */ - options_total_length += 4; - } + return wtap_optionblock_write(wdh, wdh->shb_hdr, err); } + /* we don't have a section block header already, so create a default one with no options */ + /* write block header */ bh.block_type = BLOCK_TYPE_SHB; - bh.block_total_length = (guint32)(sizeof(bh) + sizeof(shb) + options_total_length + 4); - pcapng_debug("pcapng_write_section_header_block: Total len %u, Options total len %u",bh.block_total_length, options_total_length); + bh.block_total_length = (guint32)(sizeof(bh) + sizeof(shb) + 4); + pcapng_debug("pcapng_write_section_header_block: Total len %u", bh.block_total_length); if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) return FALSE; wdh->bytes_dumped += sizeof bh; /* write block fixed content */ - /* XXX - get these values from wblock? */ shb.magic = 0x1A2B3C4D; shb.version_major = 1; shb.version_minor = 0; @@ -2827,106 +2727,6 @@ pcapng_write_section_header_block(wtap_dumper *wdh, int *err) return FALSE; wdh->bytes_dumped += sizeof shb; - /* XXX - write (optional) block options - * opt_comment 1 - * shb_hardware 2 - * shb_os 3 - * shb_user_appl 4 - */ - - if (comment_len) { - option_hdr.type = OPT_COMMENT; - option_hdr.value_length = comment_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the comments string */ - pcapng_debug("pcapng_write_section_header_block, comment:'%s' comment_len %u comment_pad_len %u" , opt_comment, comment_len, comment_pad_len); - if (!wtap_dump_file_write(wdh, opt_comment, comment_len, err)) - return FALSE; - wdh->bytes_dumped += comment_len; - - /* write padding (if any) */ - if (comment_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, comment_pad_len, err)) - return FALSE; - wdh->bytes_dumped += comment_pad_len; - } - } - - if (shb_hardware_len) { - option_hdr.type = OPT_SHB_HARDWARE; - option_hdr.value_length = shb_hardware_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the string */ - pcapng_debug("pcapng_write_section_header_block, shb_hardware:'%s' shb_hardware_len %u shb_hardware_pad_len %u" , shb_hardware, shb_hardware_len, shb_hardware_pad_len); - if (!wtap_dump_file_write(wdh, shb_hardware, shb_hardware_len, err)) - return FALSE; - wdh->bytes_dumped += shb_hardware_len; - - /* write padding (if any) */ - if (shb_hardware_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, shb_hardware_pad_len, err)) - return FALSE; - wdh->bytes_dumped += shb_hardware_pad_len; - } - } - - if (shb_os_len) { - option_hdr.type = OPT_SHB_OS; - option_hdr.value_length = shb_os_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the string */ - pcapng_debug("pcapng_write_section_header_block, shb_os:'%s' shb_os_len %u shb_os_pad_len %u" , shb_os, shb_os_len, shb_os_pad_len); - if (!wtap_dump_file_write(wdh, shb_os, shb_os_len, err)) - return FALSE; - wdh->bytes_dumped += shb_os_len; - - /* write padding (if any) */ - if (shb_os_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, shb_os_pad_len, err)) - return FALSE; - wdh->bytes_dumped += shb_os_pad_len; - } - } - - if (shb_user_appl_len) { - option_hdr.type = OPT_SHB_USERAPPL; - option_hdr.value_length = shb_user_appl_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the comments string */ - pcapng_debug("pcapng_write_section_header_block, shb_user_appl:'%s' shb_user_appl_len %u shb_user_appl_pad_len %u" , shb_user_appl, shb_user_appl_len, shb_user_appl_pad_len); - if (!wtap_dump_file_write(wdh, shb_user_appl, shb_user_appl_len, err)) - return FALSE; - wdh->bytes_dumped += shb_user_appl_len; - - /* write padding (if any) */ - if (shb_user_appl_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, shb_user_appl_pad_len, err)) - return FALSE; - wdh->bytes_dumped += shb_user_appl_pad_len; - } - } - - /* Write end of options if we have otions */ - if (have_options) { - option_hdr.type = OPT_EOFOPT; - option_hdr.value_length = 0; - if (!wtap_dump_file_write(wdh, &zero_pad, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - } - /* write block footer */ if (!wtap_dump_file_write(wdh, &bh.block_total_length, sizeof bh.block_total_length, err)) @@ -2936,603 +2736,6 @@ pcapng_write_section_header_block(wtap_dumper *wdh, int *err) return TRUE; } - -static gboolean -pcapng_write_if_descr_block(wtap_dumper *wdh, wtap_optionblock_t int_data, int *err) -{ - pcapng_block_header_t bh; - pcapng_interface_description_block_t idb; - const guint32 zero_pad = 0; - gboolean have_options = FALSE; - struct option option_hdr; /* guint16 type, guint16 value_length; */ - guint32 options_total_length = 0; - guint32 comment_len = 0, if_name_len = 0, if_description_len = 0 , if_os_len = 0, if_filter_str_len = 0; - guint32 comment_pad_len = 0, if_name_pad_len = 0, if_description_pad_len = 0, if_os_pad_len = 0, if_filter_str_pad_len = 0; - wtapng_if_descr_mandatory_t* int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(int_data); - char *opt_comment, *if_name, *if_description, *if_os; - guint64 if_speed; - guint8 if_tsresol, if_fcslen; - wtapng_if_descr_filter_t* if_filter; - - pcapng_debug("pcapng_write_if_descr_block: encap = %d (%s), snaplen = %d", - int_data_mand->link_type, - wtap_encap_string(wtap_pcap_encap_to_wtap_encap(int_data_mand->link_type)), - int_data_mand->snap_len); - - if (int_data_mand->link_type == (guint16)-1) { - *err = WTAP_ERR_UNWRITABLE_ENCAP; - return FALSE; - } - - /* Calculate options length */ - wtap_optionblock_get_option_string(int_data, OPT_COMMENT, &opt_comment); - if (opt_comment) { - have_options = TRUE; - comment_len = (guint32)strlen(opt_comment) & 0xffff; - if ((comment_len % 4)) { - comment_pad_len = 4 - (comment_len % 4); - } else { - comment_pad_len = 0; - } - options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ; - } - - /* - * if_name 2 A UTF-8 string containing the name of the device used to capture data. - */ - wtap_optionblock_get_option_string(int_data, OPT_IDB_NAME, &if_name); - if (if_name) { - have_options = TRUE; - if_name_len = (guint32)strlen(if_name) & 0xffff; - if ((if_name_len % 4)) { - if_name_pad_len = 4 - (if_name_len % 4); - } else { - if_name_pad_len = 0; - } - options_total_length = options_total_length + if_name_len + if_name_pad_len + 4 /* comment options tag */ ; - } - - /* - * if_description 3 A UTF-8 string containing the description of the device used to capture data. - */ - wtap_optionblock_get_option_string(int_data, OPT_IDB_DESCR, &if_description); - if (if_description) { - have_options = TRUE; - if_description_len = (guint32)strlen(if_description) & 0xffff; - if ((if_description_len % 4)) { - if_description_pad_len = 4 - (if_description_len % 4); - } else { - if_description_pad_len = 0; - } - options_total_length = options_total_length + if_description_len + if_description_pad_len + 4 /* comment options tag */ ; - } - /* Currently not handled - * if_IPv4addr 4 Interface network address and netmask. - * if_IPv6addr 5 Interface network address and prefix length (stored in the last byte). - * if_MACaddr 6 Interface Hardware MAC address (48 bits). 00 01 02 03 04 05 - * if_EUIaddr 7 Interface Hardware EUI address (64 bits), if available. TODO: give a good example - */ - /* - * if_speed 8 Interface speed (in bps). 100000000 for 100Mbps - */ - wtap_optionblock_get_option_uint64(int_data, OPT_IDB_SPEED, &if_speed); - if (if_speed != 0) { - have_options = TRUE; - options_total_length = options_total_length + 8 + 4; - } - /* - * if_tsresol 9 Resolution of timestamps. - */ - wtap_optionblock_get_option_uint8(int_data, OPT_IDB_TSRESOL, &if_tsresol); - if (if_tsresol != 0) { - have_options = TRUE; - options_total_length = options_total_length + 4 + 4; - } - /* Not used - * if_tzone 10 Time zone for GMT support (TODO: specify better). TODO: give a good example - */ - /* - * if_filter 11 The filter (e.g. "capture only TCP traffic") used to capture traffic. - * The first byte of the Option Data keeps a code of the filter used (e.g. if this is a libpcap string, or BPF bytecode, and more). - */ - wtap_optionblock_get_option_custom(int_data, OPT_IDB_FILTER, (void**)&if_filter); - if (if_filter->if_filter_str) { - have_options = TRUE; - if_filter_str_len = (guint32)(strlen(if_filter->if_filter_str) + 1) & 0xffff; - if ((if_filter_str_len % 4)) { - if_filter_str_pad_len = 4 - (if_filter_str_len % 4); - } else { - if_filter_str_pad_len = 0; - } - options_total_length = options_total_length + if_filter_str_len + if_filter_str_pad_len + 4 /* comment options tag */ ; - } - /* - * if_os 12 A UTF-8 string containing the name of the operating system of the machine in which this interface is installed. - */ - wtap_optionblock_get_option_string(int_data, OPT_IDB_OS, &if_os); - if (if_os) { - have_options = TRUE; - if_os_len = (guint32)strlen(if_os) & 0xffff; - if ((if_os_len % 4)) { - if_os_pad_len = 4 - (if_os_len % 4); - } else { - if_os_pad_len = 0; - } - options_total_length = options_total_length + if_os_len + if_os_pad_len + 4 /* comment options tag */ ; - } - /* - * if_fcslen 13 An integer value that specified the length of the Frame Check Sequence (in bits) for this interface. - * -1 if unknown or changes between packets, opt 13 An integer value that specified the length of the Frame Check Sequence (in bits) for this interface. - */ - wtap_optionblock_get_option_uint8(int_data, OPT_IDB_FCSLEN, &if_fcslen); - if (if_fcslen != 0) { - } - /* Not used - * if_tsoffset 14 A 64 bits integer value that specifies an offset (in seconds) that must be added to the timestamp of each packet - * to obtain the absolute timestamp of a packet. If the option is missing, the timestamps stored in the packet must be considered absolute timestamps. - */ - - if (have_options) { - /* End-of-options tag */ - options_total_length += 4; - } - - /* write block header */ - bh.block_type = BLOCK_TYPE_IDB; - bh.block_total_length = (guint32)(sizeof(bh) + sizeof(idb) + options_total_length + 4); - - if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) - return FALSE; - wdh->bytes_dumped += sizeof bh; - - /* write block fixed content */ - idb.linktype = int_data_mand->link_type; - idb.reserved = 0; - idb.snaplen = int_data_mand->snap_len; - - if (!wtap_dump_file_write(wdh, &idb, sizeof idb, err)) - return FALSE; - wdh->bytes_dumped += sizeof idb; - - /* XXX - write (optional) block options */ - if (comment_len != 0) { - option_hdr.type = OPT_COMMENT; - option_hdr.value_length = comment_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the comments string */ - pcapng_debug("pcapng_write_if_descr_block, comment:'%s' comment_len %u comment_pad_len %u" , opt_comment, comment_len, comment_pad_len); - if (!wtap_dump_file_write(wdh, opt_comment, comment_len, err)) - return FALSE; - wdh->bytes_dumped += comment_len; - - /* write padding (if any) */ - if (comment_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, comment_pad_len, err)) - return FALSE; - wdh->bytes_dumped += comment_pad_len; - } - } - /* - * if_name 2 A UTF-8 string containing the name of the device used to capture data. - */ - if (if_name_len !=0) { - option_hdr.type = OPT_IDB_NAME; - option_hdr.value_length = if_name_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the comments string */ - pcapng_debug("pcapng_write_if_descr_block, if_name:'%s' if_name_len %u if_name_pad_len %u" , if_name, if_name_len, if_name_pad_len); - if (!wtap_dump_file_write(wdh, if_name, if_name_len, err)) - return FALSE; - wdh->bytes_dumped += if_name_len; - - /* write padding (if any) */ - if (if_name_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, if_name_pad_len, err)) - return FALSE; - wdh->bytes_dumped += if_name_pad_len; - } - } - /* - * if_description 3 A UTF-8 string containing the description of the device used to capture data. - */ - if (if_description_len != 0) { - option_hdr.type = OPT_IDB_NAME; - option_hdr.value_length = if_description_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the comments string */ - pcapng_debug("pcapng_write_if_descr_block, if_description:'%s' if_description_len %u if_description_pad_len %u" , if_description, if_description_len, if_description_pad_len); - if (!wtap_dump_file_write(wdh, if_description, if_description_len, err)) - return FALSE; - wdh->bytes_dumped += if_description_len; - - /* write padding (if any) */ - if (if_description_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, if_description_pad_len, err)) - return FALSE; - wdh->bytes_dumped += if_description_pad_len; - } - } - /* Currently not handled - * if_IPv4addr 4 Interface network address and netmask. - * if_IPv6addr 5 Interface network address and prefix length (stored in the last byte). - * if_MACaddr 6 Interface Hardware MAC address (48 bits). 00 01 02 03 04 05 - * if_EUIaddr 7 Interface Hardware EUI address (64 bits), if available. TODO: give a good example - */ - /* - * if_speed 8 Interface speed (in bps). 100000000 for 100Mbps - */ - if (if_speed != 0) { - option_hdr.type = OPT_IDB_SPEED; - option_hdr.value_length = 8; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the comments string */ - pcapng_debug("pcapng_write_if_descr_block: if_speed %" G_GINT64_MODIFIER "u (bps)", if_speed); - if (!wtap_dump_file_write(wdh, &if_speed, sizeof(guint64), err)) - return FALSE; - wdh->bytes_dumped += 8; - } - /* - * if_tsresol 9 Resolution of timestamps. - * default is 6 for microsecond resolution, opt 9 Resolution of timestamps. - * If the Most Significant Bit is equal to zero, the remaining bits indicates - * the resolution of the timestamp as as a negative power of 10 - */ - if (if_tsresol != 0) { - option_hdr.type = OPT_IDB_TSRESOL; - option_hdr.value_length = 1; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the time stamp resolution */ - pcapng_debug("pcapng_write_if_descr_block: if_tsresol %u", if_tsresol); - if (!wtap_dump_file_write(wdh, &if_tsresol, 1, err)) - return FALSE; - wdh->bytes_dumped += 1; - if (!wtap_dump_file_write(wdh, &zero_pad, 3, err)) - return FALSE; - wdh->bytes_dumped += 3; - } - /* not used - * if_tzone 10 Time zone for GMT support (TODO: specify better). TODO: give a good example - */ - /* - * if_filter 11 The filter (e.g. "capture only TCP traffic") used to capture traffic. - */ - /* Libpcap string variant */ - if (if_filter_str_len !=0) { - option_hdr.type = OPT_IDB_FILTER; - option_hdr.value_length = if_filter_str_len; - /* if_filter_str_len includes the leading byte indicating filter type (libpcap str or BPF code) */ - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the zero indicating libpcap filter variant */ - if (!wtap_dump_file_write(wdh, &zero_pad, 1, err)) - return FALSE; - wdh->bytes_dumped += 1; - - /* Write the comments string */ - pcapng_debug("pcapng_write_if_descr_block, if_filter_str:'%s' if_filter_str_len %u if_filter_str_pad_len %u" , if_filter->if_filter_str, if_filter_str_len, if_filter_str_pad_len); - /* if_filter_str_len includes the leading byte indicating filter type (libpcap str or BPF code) */ - if (!wtap_dump_file_write(wdh, if_filter->if_filter_str, if_filter_str_len-1, err)) - return FALSE; - wdh->bytes_dumped += if_filter_str_len - 1; - - /* write padding (if any) */ - if (if_filter_str_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, if_filter_str_pad_len, err)) - return FALSE; - wdh->bytes_dumped += if_filter_str_pad_len; - } - } - /* - * if_os 12 A UTF-8 string containing the name of the operating system of the machine in which this interface is installed. - */ - if (if_os_len != 0) { - option_hdr.type = OPT_IDB_OS; - option_hdr.value_length = if_os_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the comments string */ - pcapng_debug("pcapng_write_if_descr_block, if_os:'%s' if_os_len %u if_os_pad_len %u" , if_os, if_os_len, if_os_pad_len); - if (!wtap_dump_file_write(wdh, if_os, if_os_len, err)) - return FALSE; - wdh->bytes_dumped += if_os_len; - - /* write padding (if any) */ - if (if_os_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, if_os_pad_len, err)) - return FALSE; - wdh->bytes_dumped += if_os_pad_len; - } - } - - if (have_options) { - option_hdr.type = OPT_EOFOPT; - option_hdr.value_length = 0; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - } - - /* - * if_fcslen 13 An integer value that specified the length of the Frame Check Sequence (in bits) for this interface. - */ - /* - * if_tsoffset 14 A 64 bits integer value that specifies an offset (in seconds) that must be added to the timestamp of each packet - * to obtain the absolute timestamp of a packet. If the option is missing, the timestamps stored in the packet must be considered absolute timestamps. - */ - - /* write block footer */ - if (!wtap_dump_file_write(wdh, &bh.block_total_length, - sizeof bh.block_total_length, err)) - return FALSE; - wdh->bytes_dumped += sizeof bh.block_total_length; - - return TRUE; -} - -static gboolean -pcapng_write_interface_statistics_block(wtap_dumper *wdh, wtap_optionblock_t if_stats, int *err) -{ - - pcapng_block_header_t bh; - pcapng_interface_statistics_block_t isb; - const guint32 zero_pad = 0; - gboolean have_options = FALSE; - struct option option_hdr; /* guint16 type, guint16 value_length; */ - guint32 options_total_length = 0; - guint32 comment_len = 0; - guint32 comment_pad_len = 0; - char *opt_comment; - guint64 isb_starttime, isb_endtime, isb_ifrecv, isb_ifdrop, isb_filteraccept, isb_osdrop, isb_usrdeliv; - wtapng_if_stats_mandatory_t* if_stats_mand; - - pcapng_debug("pcapng_write_interface_statistics_block"); - - wtap_optionblock_get_option_string(if_stats, OPT_COMMENT, &opt_comment); - /* Calculate options length */ - if (opt_comment) { - have_options = TRUE; - comment_len = (guint32)strlen(opt_comment) & 0xffff; - if ((comment_len % 4)) { - comment_pad_len = 4 - (comment_len % 4); - } else { - comment_pad_len = 0; - } - options_total_length = options_total_length + comment_len + comment_pad_len + 4 /* comment options tag */ ; - } - - wtap_optionblock_get_option_uint64(if_stats, OPT_ISB_STARTTIME, &isb_starttime); - if (isb_starttime != 0) { - have_options = TRUE; - options_total_length = options_total_length + 8 + 4 /* options tag */ ; - } - wtap_optionblock_get_option_uint64(if_stats, OPT_ISB_ENDTIME, &isb_endtime); - if (isb_endtime != 0) { - have_options = TRUE; - options_total_length = options_total_length + 8 + 4 /* options tag */ ; - } - wtap_optionblock_get_option_uint64(if_stats, OPT_ISB_IFRECV, &isb_ifrecv); - if (isb_ifrecv != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - have_options = TRUE; - options_total_length = options_total_length + 8 + 4 /* options tag */ ; - } - wtap_optionblock_get_option_uint64(if_stats, OPT_ISB_IFDROP, &isb_ifdrop); - if (isb_ifdrop != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - have_options = TRUE; - options_total_length = options_total_length + 8 + 4 /* options tag */ ; - } - wtap_optionblock_get_option_uint64(if_stats, OPT_ISB_FILTERACCEPT, &isb_filteraccept); - if (isb_filteraccept != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - have_options = TRUE; - options_total_length = options_total_length + 8 + 4 /* options tag */ ; - } - wtap_optionblock_get_option_uint64(if_stats, OPT_ISB_OSDROP, &isb_osdrop); - if (isb_osdrop != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - have_options = TRUE; - options_total_length = options_total_length + 8 + 4 /* options tag */ ; - } - wtap_optionblock_get_option_uint64(if_stats, OPT_ISB_USRDELIV, &isb_usrdeliv); - if (isb_usrdeliv != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - have_options = TRUE; - options_total_length = options_total_length + 8 + 4 /* options tag */ ; - } - - /* write block header */ - if (have_options) { - /* End-of-optios tag */ - options_total_length += 4; - } - - /* write block header */ - bh.block_type = BLOCK_TYPE_ISB; - bh.block_total_length = (guint32)(sizeof(bh) + sizeof(isb) + options_total_length + 4); - - if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) - return FALSE; - wdh->bytes_dumped += sizeof bh; - - /* write block fixed content */ - if_stats_mand = (wtapng_if_stats_mandatory_t*)wtap_optionblock_get_mandatory_data(if_stats); - - isb.interface_id = if_stats_mand->interface_id; - isb.timestamp_high = if_stats_mand->ts_high; - isb.timestamp_low = if_stats_mand->ts_low; - - if (!wtap_dump_file_write(wdh, &isb, sizeof isb, err)) - return FALSE; - wdh->bytes_dumped += sizeof isb; - - /* write (optional) block options */ - if (comment_len) { - option_hdr.type = OPT_COMMENT; - option_hdr.value_length = comment_len; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write the comments string */ - pcapng_debug("pcapng_write_interface_statistics_block, comment:'%s' comment_len %u comment_pad_len %u" , opt_comment, comment_len, comment_pad_len); - if (!wtap_dump_file_write(wdh, opt_comment, comment_len, err)) - return FALSE; - wdh->bytes_dumped += comment_len; - - /* write padding (if any) */ - if (comment_pad_len != 0) { - if (!wtap_dump_file_write(wdh, &zero_pad, comment_pad_len, err)) - return FALSE; - wdh->bytes_dumped += comment_pad_len; - } - } - /*guint64 isb_starttime */ - if (isb_starttime != 0) { - guint32 high, low; - - option_hdr.type = OPT_ISB_STARTTIME; - option_hdr.value_length = 8; - high = (guint32)((isb_starttime>>32) & 0xffffffff); - low = (guint32)(isb_starttime & 0xffffffff); - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write isb_starttime */ - pcapng_debug("pcapng_write_interface_statistics_block, isb_starttime: %" G_GINT64_MODIFIER "u" , isb_starttime); - if (!wtap_dump_file_write(wdh, &high, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - if (!wtap_dump_file_write(wdh, &low, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - } - /*guint64 isb_endtime */ - if (isb_endtime != 0) { - guint32 high, low; - - option_hdr.type = OPT_ISB_ENDTIME; - option_hdr.value_length = 8; - high = (guint32)((isb_endtime>>32) & 0xffffffff); - low = (guint32)(isb_endtime & 0xffffffff); - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write isb_endtime */ - pcapng_debug("pcapng_write_interface_statistics_block, isb_starttime: %" G_GINT64_MODIFIER "u" , isb_endtime); - if (!wtap_dump_file_write(wdh, &high, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - if (!wtap_dump_file_write(wdh, &low, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - } - /*guint64 isb_ifrecv;*/ - if (isb_ifrecv != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - option_hdr.type = OPT_ISB_IFRECV; - option_hdr.value_length = 8; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write isb_ifrecv */ - pcapng_debug("pcapng_write_interface_statistics_block, isb_ifrecv: %" G_GINT64_MODIFIER "u" , isb_ifrecv); - if (!wtap_dump_file_write(wdh, &isb_ifrecv, 8, err)) - return FALSE; - wdh->bytes_dumped += 8; - } - /*guint64 isb_ifdrop;*/ - if (isb_ifdrop != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - option_hdr.type = OPT_ISB_IFDROP; - option_hdr.value_length = 8; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write isb_ifdrop */ - pcapng_debug("pcapng_write_interface_statistics_block, isb_ifdrop: %" G_GINT64_MODIFIER "u" , isb_ifdrop); - if (!wtap_dump_file_write(wdh, &isb_ifdrop, 8, err)) - return FALSE; - wdh->bytes_dumped += 8; - } - /*guint64 isb_filteraccept;*/ - if (isb_filteraccept != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - option_hdr.type = OPT_ISB_FILTERACCEPT; - option_hdr.value_length = 8; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write isb_filteraccept */ - pcapng_debug("pcapng_write_interface_statistics_block, isb_filteraccept: %" G_GINT64_MODIFIER "u" , isb_filteraccept); - if (!wtap_dump_file_write(wdh, &isb_filteraccept, 8, err)) - return FALSE; - wdh->bytes_dumped += 8; - } - /*guint64 isb_osdrop;*/ - if (isb_osdrop != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - option_hdr.type = OPT_ISB_OSDROP; - option_hdr.value_length = 8; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write isb_osdrop */ - pcapng_debug("pcapng_write_interface_statistics_block, isb_osdrop: %" G_GINT64_MODIFIER "u" , isb_osdrop); - if (!wtap_dump_file_write(wdh, &isb_osdrop, 8, err)) - return FALSE; - wdh->bytes_dumped += 8; - } - /*guint64 isb_usrdeliv;*/ - if (isb_usrdeliv != G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) { - option_hdr.type = OPT_ISB_USRDELIV; - option_hdr.value_length = 8; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - - /* Write isb_usrdeliv */ - pcapng_debug("pcapng_write_interface_statistics_block, isb_usrdeliv: %" G_GINT64_MODIFIER "u" , isb_usrdeliv); - if (!wtap_dump_file_write(wdh, &isb_usrdeliv, 8, err)) - return FALSE; - wdh->bytes_dumped += 8; - } - - if (have_options) { - option_hdr.type = OPT_EOFOPT; - option_hdr.value_length = 0; - if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) - return FALSE; - wdh->bytes_dumped += 4; - } - - /* write block footer */ - if (!wtap_dump_file_write(wdh, &bh.block_total_length, - sizeof bh.block_total_length, err)) - return FALSE; - wdh->bytes_dumped += sizeof bh.block_total_length; - - return TRUE; - -} - - static gboolean pcapng_write_enhanced_packet_block(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, @@ -4056,7 +3259,7 @@ static gboolean pcapng_dump_finish(wtap_dumper *wdh, int *err) if_stats = g_array_index(int_data_mand->interface_statistics, wtap_optionblock_t, j); pcapng_debug("pcapng_dump_finish: write ISB for interface %u", ((wtapng_if_stats_mandatory_t*)wtap_optionblock_get_mandatory_data(if_stats))->interface_id); - if (!pcapng_write_interface_statistics_block(wdh, if_stats, err)) { + if (!wtap_optionblock_write(wdh, if_stats, err)) { return FALSE; } } @@ -4098,11 +3301,11 @@ pcapng_dump_open(wtap_dumper *wdh, int *err) for (i = 0; i < wdh->interface_data->len; i++) { /* Get the interface description */ - wtap_optionblock_t int_data; + wtap_optionblock_t idb; - int_data = g_array_index(wdh->interface_data, wtap_optionblock_t, i); + idb = g_array_index(wdh->interface_data, wtap_optionblock_t, i); - if (!pcapng_write_if_descr_block(wdh, int_data, err)) { + if (!wtap_optionblock_write(wdh, idb, err)) { return FALSE; } diff --git a/wiretap/pcapng.h b/wiretap/pcapng.h index 7827a83482..49a896a0f4 100644 --- a/wiretap/pcapng.h +++ b/wiretap/pcapng.h @@ -112,6 +112,50 @@ #define OPT_ISB_OSDROP 0x0007 #define OPT_ISB_USRDELIV 0x0008 +/* pcapng: common block header file encoding for every block type */ +typedef struct pcapng_block_header_s { + guint32 block_type; + guint32 block_total_length; + /* x bytes block_body */ + /* guint32 block_total_length */ +} pcapng_block_header_t; + +/* pcapng: section header block file encoding */ +typedef struct pcapng_section_header_block_s { + /* pcapng_block_header_t */ + guint32 magic; + guint16 version_major; + guint16 version_minor; + guint64 section_length; /* might be -1 for unknown */ + /* ... Options ... */ +} pcapng_section_header_block_t; + +/* pcapng: interface description block file encoding */ +typedef struct pcapng_interface_description_block_s { + guint16 linktype; + guint16 reserved; + guint32 snaplen; + /* ... Options ... */ +} pcapng_interface_description_block_t; + +/* pcapng: interface statistics block file encoding */ +typedef struct pcapng_interface_statistics_block_s { + guint32 interface_id; + guint32 timestamp_high; + guint32 timestamp_low; + /* ... Options ... */ +} pcapng_interface_statistics_block_t; + +struct pcapng_option_header { + guint16 type; + guint16 value_length; +}; + +/* + * Minimum IDB size = minimum block size + size of fixed length portion of IDB. + */ +#define MIN_IDB_SIZE ((guint32)(MIN_BLOCK_SIZE + sizeof(pcapng_interface_description_block_t))) + wtap_open_return_val pcapng_open(wtap *wth, int *err, gchar **err_info); gboolean pcapng_dump_open(wtap_dumper *wdh, int *err); int pcapng_dump_can_write_encap(int encap); diff --git a/wiretap/wtap_opttypes.c b/wiretap/wtap_opttypes.c index e72d77d907..3878178d9a 100644 --- a/wiretap/wtap_opttypes.c +++ b/wiretap/wtap_opttypes.c @@ -27,25 +27,50 @@ #include "wtap_opttypes.h" #include "wtap-int.h" #include "pcapng.h" +#include "pcapng_module.h" + +#if 0 +#define wtap_debug(...) g_warning(__VA_ARGS__) +#else +#define wtap_debug(...) +#endif typedef void (*wtap_block_create_func)(wtap_optionblock_t block); typedef void (*wtap_mand_free_func)(wtap_optionblock_t block); typedef void (*wtap_mand_copy_func)(wtap_optionblock_t dest_block, wtap_optionblock_t src_block); +typedef gboolean (*wtap_write_func)(struct wtap_dumper *wdh, wtap_optionblock_t block, int *err); typedef struct wtap_opt_register { const char *name; /**< name of block */ const char *description; /**< human-readable description of block */ wtap_block_create_func create; + wtap_write_func write; wtap_mand_free_func free_mand; wtap_mand_copy_func copy_mand; } wtap_opt_register_t; +typedef struct wtap_optblock_internal { + const char *name; /**< name of option */ + const char *description; /**< human-readable description of option */ + guint number; /**< Option index */ + wtap_opttype_e type; /**< type of that option */ + wtap_opttype_option_write_size write_size; /**< Number of bytes to write to file (0 for don't write) */ + wtap_opttype_option_write write_data; /**< write option data to dumper */ +} wtap_optblock_internal_t; + +typedef struct wtap_optblock_value { + wtap_optblock_internal_t* info; + wtap_option_type option; /**< pointer to variable storing the value */ + wtap_option_type default_val; /**< the default value of the option */ +} wtap_optblock_value_t; + struct wtap_optionblock { wtap_opt_register_t* info; void* mandatory_data; - GArray* options; + GArray* option_infos; /* Only want to keep 1 copy of "static" option information */ + GArray* option_values; }; /* Keep track of wtap_opt_register_t's via their id number */ @@ -72,15 +97,15 @@ void* wtap_optionblock_get_mandatory_data(wtap_optionblock_t block) return block->mandatory_data; } -static wtap_opttype_t* wtap_optionblock_get_option(wtap_optionblock_t block, guint option_id) +static wtap_optblock_value_t* wtap_optionblock_get_option(wtap_optionblock_t block, guint option_id) { guint i; - wtap_opttype_t* opttype = NULL; + wtap_optblock_value_t* opttype = NULL; - for (i = 0; i < block->options->len; i++) + for (i = 0; i < block->option_values->len; i++) { - opttype = g_array_index(block->options, wtap_opttype_t*, i); - if (opttype->number == option_id) + opttype = g_array_index(block->option_values, wtap_optblock_value_t*, i); + if (opttype->info->number == option_id) return opttype; } @@ -96,6 +121,8 @@ wtap_optionblock_t wtap_optionblock_create(wtap_optionblock_type_t block_type) block = g_new(struct wtap_optionblock, 1); block->info = block_list[block_type]; + block->option_infos = g_array_new(FALSE, FALSE, sizeof(wtap_optblock_internal_t*)); + block->option_values = g_array_new(FALSE, FALSE, sizeof(wtap_optblock_value_t*)); block->info->create(block); return block; @@ -104,11 +131,11 @@ wtap_optionblock_t wtap_optionblock_create(wtap_optionblock_type_t block_type) static void wtap_optionblock_free_options(wtap_optionblock_t block) { guint i; - wtap_opttype_t* opttype = NULL; + wtap_optblock_value_t* opttype = NULL; - for (i = 0; i < block->options->len; i++) { - opttype = g_array_index(block->options, wtap_opttype_t*, i); - switch(opttype->type) + for (i = 0; i < block->option_values->len; i++) { + opttype = g_array_index(block->option_values, wtap_optblock_value_t*, i); + switch(opttype->info->type) { case WTAP_OPTTYPE_STRING: g_free(opttype->option.stringval); @@ -135,8 +162,10 @@ void wtap_optionblock_free(wtap_optionblock_t block) g_free(block->mandatory_data); wtap_optionblock_free_options(block); - if (block->options != NULL) - g_array_free(block->options, FALSE); + if (block->option_infos != NULL) + g_array_free(block->option_infos, FALSE); + if (block->option_values != NULL) + g_array_free(block->option_values, FALSE); g_free(block); } } @@ -144,7 +173,8 @@ void wtap_optionblock_free(wtap_optionblock_t block) void wtap_optionblock_copy_options(wtap_optionblock_t dest_block, wtap_optionblock_t src_block) { guint i; - wtap_opttype_t *dest_opttype, *src_opttype; + wtap_optblock_internal_t *src_internal; + wtap_optblock_value_t *dest_value, *src_value; if (dest_block->info->copy_mand != NULL) dest_block->info->copy_mand(dest_block, src_block); @@ -152,290 +182,474 @@ void wtap_optionblock_copy_options(wtap_optionblock_t dest_block, wtap_optionblo /* Copy the options. For now, don't remove any options that are in destination * but not source. */ - for (i = 0; i < src_block->options->len; i++) + for (i = 0; i < src_block->option_values->len; i++) { - src_opttype = g_array_index(src_block->options, wtap_opttype_t*, i); - dest_opttype = wtap_optionblock_get_option(dest_block, src_opttype->number); - if (dest_opttype == NULL) + src_internal = g_array_index(src_block->option_infos, wtap_optblock_internal_t*, i); + src_value = g_array_index(src_block->option_values, wtap_optblock_value_t*, i); + dest_value = wtap_optionblock_get_option(dest_block, src_internal->number); + if (dest_value == NULL) { - /* Option doesn't exist, add it */ - switch(src_opttype->type) - { - case WTAP_OPTTYPE_UINT8: - wtap_optionblock_add_option_uint8(dest_block, src_opttype->number, src_opttype->name, src_opttype->description, - src_opttype->option.uint8val, src_opttype->default_val.uint8val); - break; - case WTAP_OPTTYPE_UINT64: - wtap_optionblock_add_option_uint64(dest_block, src_opttype->number, src_opttype->name, src_opttype->description, - src_opttype->option.uint64val, src_opttype->default_val.uint64val); - break; - case WTAP_OPTTYPE_STRING: - wtap_optionblock_add_option_string(dest_block, src_opttype->number, src_opttype->name, src_opttype->description, - src_opttype->option.stringval, src_opttype->default_val.stringval); - break; - case WTAP_OPTTYPE_CUSTOM: - wtap_optionblock_add_option_custom(dest_block, src_opttype->number, src_opttype->name, src_opttype->description, - src_opttype->option.customval.data, src_opttype->default_val.customval.data, - src_opttype->option.customval.size, src_opttype->option.customval.free_func); - break; - } + wtap_optblock_reg_t reg_optblock; + + reg_optblock.name = src_internal->name; + reg_optblock.description = src_internal->description; + reg_optblock.type = src_internal->type; + reg_optblock.option = src_value->option; + reg_optblock.default_val = src_value->default_val; + + wtap_optionblock_add_option(dest_block, src_internal->number, ®_optblock); } else { /* Option exists, replace it */ - switch(src_opttype->type) + switch(src_internal->type) { case WTAP_OPTTYPE_UINT8: - dest_opttype->option.uint8val = src_opttype->option.uint8val; + dest_value->option.uint8val = src_value->option.uint8val; break; case WTAP_OPTTYPE_UINT64: - dest_opttype->option.uint64val = src_opttype->option.uint64val; + dest_value->option.uint64val = src_value->option.uint64val; break; case WTAP_OPTTYPE_STRING: - g_free(dest_opttype->option.stringval); - dest_opttype->option.stringval = g_strdup(src_opttype->option.stringval); + g_free(dest_value->option.stringval); + dest_value->option.stringval = g_strdup(src_value->option.stringval); break; case WTAP_OPTTYPE_CUSTOM: - dest_opttype->option.customval.free_func(dest_opttype->option.customval.data); - g_free(dest_opttype->option.customval.data); - dest_opttype->option.customval.data = g_memdup(src_opttype->option.customval.data, src_opttype->option.customval.size); + dest_value->option.customval.free_func(dest_value->option.customval.data); + g_free(dest_value->option.customval.data); + dest_value->option.customval.data = g_memdup(src_value->option.customval.data, src_value->option.customval.size); break; } } } } -int wtap_optionblock_add_option_string(wtap_optionblock_t block, guint option_id, - const char *name, const char *description, char* opt_value, char* default_value) +gboolean wtap_optionblock_write(struct wtap_dumper *wdh, wtap_optionblock_t block, int *err) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + if ((block == NULL) || (block->info->write == NULL)) + { + *err = WTAP_ERR_INTERNAL; + return FALSE; + } + + return block->info->write(wdh, block, err); +} + +static guint32 wtap_optionblock_get_option_write_size(wtap_optionblock_t block) +{ + guint i; + guint32 options_total_length = 0, length; + wtap_optblock_value_t *value; + + for (i = 0; i < block->option_values->len; i++) + { + value = g_array_index(block->option_values, wtap_optblock_value_t*, i); + if ((value->info->write_size != NULL) && (value->info->write_data != NULL)) + { + length = value->info->write_size(&value->option); + options_total_length += length; + /* Add bytes for option header if option should be written */ + if (length > 0) + options_total_length += 4; + } + } + + return options_total_length; +} + +static gboolean wtap_optionblock_write_options(struct wtap_dumper *wdh, wtap_optionblock_t block, guint32 options_total_length, int *err) +{ + guint i; + wtap_optblock_value_t *value; + struct pcapng_option_header option_hdr; + guint32 length; + + /* Check if we have at least 1 option to write */ + if (options_total_length == 0) + return TRUE; + + for (i = 0; i < block->option_values->len; i++) + { + value = g_array_index(block->option_values, wtap_optblock_value_t*, i); + if ((value->info->write_size != NULL) && (value->info->write_data != NULL) && + ((length = value->info->write_size(&value->option)) > 0)) + { + /* Write the option */ + wtap_debug("wtap_optionblock_write %s, field:'%s' length: %u", block->description, value->info->description, length); + + /* String options don't consider pad bytes part of the length, so readjust here */ + if (value->info->type == WTAP_OPTTYPE_STRING) + length = (guint32)strlen(value->option.stringval) & 0xffff; + + option_hdr.type = value->info->number; + option_hdr.value_length = length; + if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) + return FALSE; + wdh->bytes_dumped += 4; + + if (!value->info->write_data(wdh, &value->option, err)) + return FALSE; + } + } + + /* Write end of options */ + option_hdr.type = OPT_EOFOPT; + option_hdr.value_length = 0; + if (!wtap_dump_file_write(wdh, &option_hdr, 4, err)) + return FALSE; + wdh->bytes_dumped += 4; + return TRUE; +} + +int wtap_optionblock_add_option(wtap_optionblock_t block, guint option_id, wtap_optblock_reg_t* option) +{ + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); + wtap_optblock_internal_t *opt_internal; /* Option already exists */ - if (opttype != NULL) + if (opt_value != NULL) return WTAP_OPTTYPE_ALREADY_EXISTS; - opttype = g_new(wtap_opttype_t, 1); + opt_value = g_new0(wtap_optblock_value_t, 1); + opt_internal = g_new(wtap_optblock_internal_t, 1); - opttype->name = name; - opttype->description = description; - opttype->number = option_id; - opttype->type = WTAP_OPTTYPE_STRING; - opttype->option.stringval = g_strdup(opt_value); - opttype->default_val.stringval = default_value; + opt_internal->name = option->name; + opt_internal->description = option->description; + opt_internal->number = option_id; + opt_internal->type = option->type; + opt_internal->write_size = option->write_size_func; + opt_internal->write_data = option->write_func; - g_array_append_val(block->options, opttype); + opt_value->info = opt_internal; + + switch(option->type) + { + case WTAP_OPTTYPE_UINT8: + opt_value->option.uint8val = option->option.uint8val; + opt_value->default_val.uint8val = option->default_val.uint8val; + break; + case WTAP_OPTTYPE_UINT64: + opt_value->option.uint64val = option->option.uint64val; + opt_value->default_val.uint64val = option->default_val.uint64val; + break; + case WTAP_OPTTYPE_STRING: + opt_value->option.stringval = g_strdup(option->option.stringval); + opt_value->default_val.stringval = option->default_val.stringval; + break; + case WTAP_OPTTYPE_CUSTOM: + opt_value->option.customval.size = option->option.customval.size; + opt_value->option.customval.data = g_memdup(option->option.customval.data, option->option.customval.size); + opt_value->option.customval.free_func = option->option.customval.free_func; + opt_value->default_val.customval.size = option->default_val.customval.size; + opt_value->default_val.customval.data = g_memdup(option->default_val.customval.data, option->default_val.customval.size); + opt_value->default_val.customval.free_func = option->default_val.customval.free_func; + break; + } + + g_array_append_val(block->option_infos, opt_internal); + g_array_append_val(block->option_values, opt_value); return WTAP_OPTTYPE_SUCCESS; } -int wtap_optionblock_set_option_string(wtap_optionblock_t block, guint option_id, char* opt_value) +int wtap_optionblock_set_option_string(wtap_optionblock_t block, guint option_id, char* value) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); /* Didn't find the option */ - if (opttype == NULL) + if (opt_value == NULL) return WTAP_OPTTYPE_NOT_FOUND; - if (opttype->type != WTAP_OPTTYPE_STRING) + if (opt_value->info->type != WTAP_OPTTYPE_STRING) return WTAP_OPTTYPE_TYPE_MISMATCH; - g_free(opttype->option.stringval); - opttype->option.stringval = g_strdup(opt_value); + g_free(opt_value->option.stringval); + opt_value->option.stringval = g_strdup(value); return WTAP_OPTTYPE_SUCCESS; } -int wtap_optionblock_get_option_string(wtap_optionblock_t block, guint option_id, char** opt_value) +int wtap_optionblock_get_option_string(wtap_optionblock_t block, guint option_id, char** value) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); /* Didn't find the option */ - if (opttype == NULL) + if (opt_value == NULL) return WTAP_OPTTYPE_NOT_FOUND; - if (opttype->type != WTAP_OPTTYPE_STRING) + if (opt_value->info->type != WTAP_OPTTYPE_STRING) return WTAP_OPTTYPE_TYPE_MISMATCH; - *opt_value = opttype->option.stringval; + *value = opt_value->option.stringval; return WTAP_OPTTYPE_SUCCESS; } -int wtap_optionblock_add_option_uint64(wtap_optionblock_t block, guint option_id, - const char *name, const char *description, guint64 opt_value, guint64 default_value) +guint32 wtap_opttype_write_size_string(wtap_option_type* data) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + guint32 size, pad; + if ((data == NULL) ||(data->stringval == NULL)) + return 0; - /* Option already exists */ - if (opttype != NULL) - return WTAP_OPTTYPE_ALREADY_EXISTS; + size = (guint32)strlen(data->stringval) & 0xffff; + if ((size % 4)) { + pad = 4 - (size % 4); + } else { + pad = 0; + } - opttype = g_new(wtap_opttype_t, 1); - - opttype->name = name; - opttype->description = description; - opttype->number = option_id; - opttype->type = WTAP_OPTTYPE_UINT64; - opttype->option.uint64val = opt_value; - opttype->default_val.uint64val = default_value; - - g_array_append_val(block->options, opttype); - return WTAP_OPTTYPE_SUCCESS; + return size+pad; } -int wtap_optionblock_set_option_uint64(wtap_optionblock_t block, guint option_id, guint64 opt_value) +gboolean wtap_opttype_write_data_string(struct wtap_dumper* wdh, wtap_option_type* data, int *err) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + guint32 size = (guint32)strlen(data->stringval) & 0xffff; + guint32 pad; + const guint32 zero_pad = 0; + + if (!wtap_dump_file_write(wdh, data->stringval, size, err)) + return FALSE; + wdh->bytes_dumped += size; + + if ((size % 4)) { + pad = 4 - (size % 4); + } else { + pad = 0; + } + + /* write padding (if any) */ + if (pad != 0) { + if (!wtap_dump_file_write(wdh, &zero_pad, pad, err)) + return FALSE; + wdh->bytes_dumped += pad; + } + + return TRUE; +} + +int wtap_optionblock_set_option_uint64(wtap_optionblock_t block, guint option_id, guint64 value) +{ + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); /* Didn't find the option */ - if (opttype == NULL) + if (opt_value == NULL) return WTAP_OPTTYPE_NOT_FOUND; - if (opttype->type != WTAP_OPTTYPE_UINT64) + if (opt_value->info->type != WTAP_OPTTYPE_UINT64) return WTAP_OPTTYPE_TYPE_MISMATCH; - opttype->option.uint64val = opt_value; + opt_value->option.uint64val = value; return WTAP_OPTTYPE_SUCCESS; } -int wtap_optionblock_get_option_uint64(wtap_optionblock_t block, guint option_id, guint64* opt_value) +int wtap_optionblock_get_option_uint64(wtap_optionblock_t block, guint option_id, guint64* value) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); /* Didn't find the option */ - if (opttype == NULL) + if (opt_value == NULL) return WTAP_OPTTYPE_NOT_FOUND; - if (opttype->type != WTAP_OPTTYPE_UINT64) + if (opt_value->info->type != WTAP_OPTTYPE_UINT64) return WTAP_OPTTYPE_TYPE_MISMATCH; - *opt_value = opttype->option.uint64val; + *value = opt_value->option.uint64val; return WTAP_OPTTYPE_SUCCESS; } -int wtap_optionblock_add_option_uint8(wtap_optionblock_t block, guint option_id, - const char *name, const char *description, guint8 opt_value, guint8 default_value) +guint32 wtap_opttype_write_uint64_not0(wtap_option_type* data) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + if (data == NULL) + return 0; - /* Option already exists */ - if (opttype != NULL) - return WTAP_OPTTYPE_ALREADY_EXISTS; + if (data->uint64val == 0) + return 0; - opttype = g_new(wtap_opttype_t, 1); - - opttype->name = name; - opttype->description = description; - opttype->number = option_id; - opttype->type = WTAP_OPTTYPE_UINT8; - opttype->option.uint8val = opt_value; - opttype->default_val.uint8val = default_value; - - g_array_append_val(block->options, opttype); - return WTAP_OPTTYPE_SUCCESS; + /* value */ + return 8; } -int wtap_optionblock_set_option_uint8(wtap_optionblock_t block, guint option_id, guint8 opt_value) +guint32 wtap_opttype_write_uint64_not_minus1(wtap_option_type* data) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + if (data == NULL) + return 0; + + if (data->uint64val == G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) + return 0; + + /* value */ + return 8; +} + +gboolean wtap_opttype_write_data_uint64(struct wtap_dumper* wdh, wtap_option_type* data, int *err) +{ + if (!wtap_dump_file_write(wdh, &data->uint64val, sizeof(guint64), err)) + return FALSE; + wdh->bytes_dumped += 8; + return TRUE; +} + +int wtap_optionblock_set_option_uint8(wtap_optionblock_t block, guint option_id, guint8 value) +{ + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); /* Didn't find the option */ - if (opttype == NULL) + if (opt_value == NULL) return WTAP_OPTTYPE_NOT_FOUND; - if (opttype->type != WTAP_OPTTYPE_UINT8) + if (opt_value->info->type != WTAP_OPTTYPE_UINT8) return WTAP_OPTTYPE_TYPE_MISMATCH; - opttype->option.uint8val = opt_value; + opt_value->option.uint8val = value; return WTAP_OPTTYPE_SUCCESS; } -int wtap_optionblock_get_option_uint8(wtap_optionblock_t block, guint option_id, guint8* opt_value) +int wtap_optionblock_get_option_uint8(wtap_optionblock_t block, guint option_id, guint8* value) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); /* Didn't find the option */ - if (opttype == NULL) + if (opt_value == NULL) return WTAP_OPTTYPE_NOT_FOUND; - if (opttype->type != WTAP_OPTTYPE_UINT8) + if (opt_value->info->type != WTAP_OPTTYPE_UINT8) return WTAP_OPTTYPE_TYPE_MISMATCH; - *opt_value = opttype->option.uint8val; + *value = opt_value->option.uint8val; return WTAP_OPTTYPE_SUCCESS; } -int wtap_optionblock_add_option_custom(wtap_optionblock_t block, guint option_id, - const char *name, const char *description, void* opt_value, void* default_value, - guint size, wtap_opttype_free_custom_func free_func) +guint32 wtap_opttype_write_uint8_not0(wtap_option_type* data) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + if (data == NULL) + return 0; - /* Option already exists */ - if (opttype != NULL) - return WTAP_OPTTYPE_ALREADY_EXISTS; + if (data->uint8val == 0) + return 0; - opttype = g_new(wtap_opttype_t, 1); - - opttype->name = name; - opttype->description = description; - opttype->number = option_id; - opttype->type = WTAP_OPTTYPE_CUSTOM; - opttype->option.customval.size = size; - opttype->option.customval.data = g_memdup(opt_value, size); - opttype->option.customval.free_func = free_func; - opttype->default_val.customval.size = size; - opttype->default_val.customval.data = g_memdup(default_value, size); - opttype->default_val.customval.free_func = free_func; - - g_array_append_val(block->options, opttype); - return WTAP_OPTTYPE_SUCCESS; + /* padding to 32 bits */ + return 4; } -int wtap_optionblock_set_option_custom(wtap_optionblock_t block, guint option_id, void* opt_value) +gboolean wtap_opttype_write_data_uint8(struct wtap_dumper* wdh, wtap_option_type* data, int *err) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + const guint32 zero_pad = 0; + + if (!wtap_dump_file_write(wdh, &data->uint8val, 1, err)) + return FALSE; + wdh->bytes_dumped += 1; + + if (!wtap_dump_file_write(wdh, &zero_pad, 3, err)) + return FALSE; + wdh->bytes_dumped += 3; + + return TRUE; +} + +int wtap_optionblock_set_option_custom(wtap_optionblock_t block, guint option_id, void* value) +{ + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); void* prev_value; /* Didn't find the option */ - if (opttype == NULL) + if (opt_value == NULL) return WTAP_OPTTYPE_NOT_FOUND; - if (opttype->type != WTAP_OPTTYPE_CUSTOM) + if (opt_value->info->type != WTAP_OPTTYPE_CUSTOM) return WTAP_OPTTYPE_TYPE_MISMATCH; - prev_value = opttype->option.customval.data; - opttype->option.customval.data = g_memdup(opt_value, opttype->option.customval.size); + prev_value = opt_value->option.customval.data; + opt_value->option.customval.data = g_memdup(value, opt_value->option.customval.size); /* Free after memory is duplicated in case structure was manipulated with a "get then set" */ g_free(prev_value); return WTAP_OPTTYPE_SUCCESS; } -int wtap_optionblock_get_option_custom(wtap_optionblock_t block, guint option_id, void** opt_value) +int wtap_optionblock_get_option_custom(wtap_optionblock_t block, guint option_id, void** value) { - wtap_opttype_t* opttype = wtap_optionblock_get_option(block, option_id); + wtap_optblock_value_t* opt_value = wtap_optionblock_get_option(block, option_id); /* Didn't find the option */ - if (opttype == NULL) + if (opt_value == NULL) return WTAP_OPTTYPE_NOT_FOUND; - if (opttype->type != WTAP_OPTTYPE_CUSTOM) + if (opt_value->info->type != WTAP_OPTTYPE_CUSTOM) return WTAP_OPTTYPE_TYPE_MISMATCH; - *opt_value = opttype->option.customval.data; + *value = opt_value->option.customval.data; return WTAP_OPTTYPE_SUCCESS; } static void shb_create(wtap_optionblock_t block) { + static wtap_optblock_reg_t comment_option = {"opt_comment", "Optional comment", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + static wtap_optblock_reg_t hardware_option = {"hardware", "SBH Hardware", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + static wtap_optblock_reg_t os_option = {"os", "SBH Operating System", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + static wtap_optblock_reg_t user_appl_option = {"user_appl", "SBH User Application", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + wtapng_mandatory_section_t* section_mand = g_new(wtapng_mandatory_section_t, 1); + /* Set proper values for the union */ + comment_option.option.stringval = NULL; + comment_option.default_val.stringval = NULL; + hardware_option.option.stringval = NULL; + hardware_option.default_val.stringval = NULL; + os_option.option.stringval = NULL; + os_option.default_val.stringval = NULL; + user_appl_option.option.stringval = NULL; + user_appl_option.default_val.stringval = NULL; + section_mand->section_length = -1; block->mandatory_data = section_mand; - block->options = g_array_new(FALSE, FALSE, sizeof(wtap_opttype_t*)); - wtap_optionblock_add_option_string(block, OPT_COMMENT, "opt_comment", "Optional comment", NULL, NULL); - wtap_optionblock_add_option_string(block, OPT_SHB_HARDWARE, "hardware", "SBH Hardware", NULL, NULL); - wtap_optionblock_add_option_string(block, OPT_SHB_OS, "os", "SBH Operating System", NULL, NULL); - wtap_optionblock_add_option_string(block, OPT_SHB_USERAPPL, "user_appl", "SBH User Application", NULL, NULL); + wtap_optionblock_add_option(block, OPT_COMMENT, &comment_option); + wtap_optionblock_add_option(block, OPT_SHB_HARDWARE, &hardware_option); + wtap_optionblock_add_option(block, OPT_SHB_OS, &os_option); + wtap_optionblock_add_option(block, OPT_SHB_USERAPPL, &user_appl_option); +} + +static gboolean shb_write(struct wtap_dumper *wdh, wtap_optionblock_t block, int *err) +{ + pcapng_block_header_t bh; + pcapng_section_header_block_t shb; + wtapng_mandatory_section_t* mand_data = (wtapng_mandatory_section_t*)block->mandatory_data; + guint32 options_total_length; + + wtap_debug("write_section_header_block: Have shb_hdr"); + + options_total_length = wtap_optionblock_get_option_write_size(block); + if (options_total_length > 0) + { + /* End-of-options tag */ + options_total_length += 4; + } + + /* write block header */ + bh.block_type = BLOCK_TYPE_SHB; + bh.block_total_length = (guint32)(sizeof(bh) + sizeof(shb) + options_total_length + 4); + + if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) + return FALSE; + wdh->bytes_dumped += sizeof bh; + + /* write block fixed content */ + shb.magic = 0x1A2B3C4D; + shb.version_major = 1; + shb.version_minor = 0; + shb.section_length = mand_data->section_length; + + if (!wtap_dump_file_write(wdh, &shb, sizeof shb, err)) + return FALSE; + wdh->bytes_dumped += sizeof shb; + + if (!wtap_optionblock_write_options(wdh, block, options_total_length, err)) + return FALSE; + + /* write block footer */ + if (!wtap_dump_file_write(wdh, &bh.block_total_length, + sizeof bh.block_total_length, err)) + return FALSE; + wdh->bytes_dumped += sizeof bh.block_total_length; + + return TRUE; } static void shb_copy_mand(wtap_optionblock_t dest_block, wtap_optionblock_t src_block) @@ -445,25 +659,101 @@ static void shb_copy_mand(wtap_optionblock_t dest_block, wtap_optionblock_t src_ static void nrb_create(wtap_optionblock_t block) { - block->mandatory_data = NULL; - block->options = g_array_new(FALSE, FALSE, sizeof(wtap_opttype_t*)); + static wtap_optblock_reg_t comment_option = {"opt_comment", "Optional comment", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; - wtap_optionblock_add_option_string(block, OPT_COMMENT, "opt_comment", "Optional comment", NULL, NULL); + /* Set proper values for the union */ + comment_option.option.stringval = NULL; + comment_option.default_val.stringval = NULL; + + block->mandatory_data = NULL; + + wtap_optionblock_add_option(block, OPT_COMMENT, &comment_option); } static void isb_create(wtap_optionblock_t block) { - block->mandatory_data = g_new0(wtapng_if_stats_mandatory_t, 1); - block->options = g_array_new(FALSE, FALSE, sizeof(wtap_opttype_t*)); + static wtap_optblock_reg_t comment_option = {"opt_comment", "Optional comment", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + static wtap_optblock_reg_t starttime_option = {"start_time", "Start Time", WTAP_OPTTYPE_UINT64, wtap_opttype_write_uint64_not0, wtap_opttype_write_data_uint64, {0}, {0}}; + static wtap_optblock_reg_t endtime_option = {"end_time", "End Time", WTAP_OPTTYPE_UINT64, wtap_opttype_write_uint64_not0, wtap_opttype_write_data_uint64, {0}, {0}}; + static wtap_optblock_reg_t rcv_pkt_option = {"recv", "Receive Packets", WTAP_OPTTYPE_UINT64, wtap_opttype_write_uint64_not_minus1, wtap_opttype_write_data_uint64, {0}, {0}}; + static wtap_optblock_reg_t drop_pkt_option = {"drop", "Dropped Packets", WTAP_OPTTYPE_UINT64, wtap_opttype_write_uint64_not_minus1, wtap_opttype_write_data_uint64, {0}, {0}}; + static wtap_optblock_reg_t filteraccept_option = {"filter_accept", "Filter Accept", WTAP_OPTTYPE_UINT64, wtap_opttype_write_uint64_not_minus1, wtap_opttype_write_data_uint64, {0}, {0}}; + static wtap_optblock_reg_t os_drop_option = {"os_drop", "OS Dropped Packets", WTAP_OPTTYPE_UINT64, wtap_opttype_write_uint64_not_minus1, wtap_opttype_write_data_uint64, {0}, {0}}; + static wtap_optblock_reg_t user_deliv_option = {"user_deliv", "User Delivery", WTAP_OPTTYPE_UINT64, wtap_opttype_write_uint64_not_minus1, wtap_opttype_write_data_uint64, {0}, {0}}; - wtap_optionblock_add_option_string(block, OPT_COMMENT, "opt_comment", "Optional comment", NULL, NULL); - wtap_optionblock_add_option_uint64(block, OPT_ISB_STARTTIME, "start_time", "Start Time", 0, 0); - wtap_optionblock_add_option_uint64(block, OPT_ISB_ENDTIME, "end_time", "End Time", 0, 0); - wtap_optionblock_add_option_uint64(block, OPT_ISB_IFRECV, "recv", "Receive Packets", G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF), G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)); - wtap_optionblock_add_option_uint64(block, OPT_ISB_IFDROP, "drop", "Dropped Packets", G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF), G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)); - wtap_optionblock_add_option_uint64(block, OPT_ISB_FILTERACCEPT, "filter_accept", "Filter Accept", G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF), G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)); - wtap_optionblock_add_option_uint64(block, OPT_ISB_OSDROP, "os_drop", "OS Dropped Packets", G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF), G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)); - wtap_optionblock_add_option_uint64(block, OPT_ISB_USRDELIV, "user_deliv", "User Delivery", G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF), G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)); + block->mandatory_data = g_new0(wtapng_if_stats_mandatory_t, 1); + + /* Set proper values for the union */ + comment_option.option.stringval = NULL; + comment_option.default_val.stringval = NULL; + starttime_option.option.uint64val = 0; + starttime_option.default_val.uint64val = 0; + endtime_option.option.uint64val = 0; + endtime_option.default_val.uint64val = 0; + rcv_pkt_option.option.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + rcv_pkt_option.default_val.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + drop_pkt_option.option.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + drop_pkt_option.default_val.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + filteraccept_option.option.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + filteraccept_option.default_val.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + os_drop_option.option.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + os_drop_option.default_val.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + user_deliv_option.option.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + user_deliv_option.default_val.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + + wtap_optionblock_add_option(block, OPT_COMMENT, &comment_option); + wtap_optionblock_add_option(block, OPT_ISB_STARTTIME, &starttime_option); + wtap_optionblock_add_option(block, OPT_ISB_ENDTIME, &endtime_option); + wtap_optionblock_add_option(block, OPT_ISB_IFRECV, &rcv_pkt_option); + wtap_optionblock_add_option(block, OPT_ISB_IFDROP, &drop_pkt_option); + wtap_optionblock_add_option(block, OPT_ISB_FILTERACCEPT, &filteraccept_option); + wtap_optionblock_add_option(block, OPT_ISB_OSDROP, &os_drop_option); + wtap_optionblock_add_option(block, OPT_ISB_USRDELIV, &user_deliv_option); +} + +static gboolean isb_write(struct wtap_dumper *wdh, wtap_optionblock_t block, int *err) +{ + pcapng_block_header_t bh; + pcapng_interface_statistics_block_t isb; + guint32 options_total_length; + wtapng_if_stats_mandatory_t* mand_data = (wtapng_if_stats_mandatory_t*)block->mandatory_data; + + wtap_debug("write_interface_statistics_block"); + + options_total_length = wtap_optionblock_get_option_write_size(block); + if (options_total_length > 0) + { + /* End-of-options tag */ + options_total_length += 4; + } + + /* write block header */ + bh.block_type = BLOCK_TYPE_ISB; + bh.block_total_length = (guint32)(sizeof(bh) + sizeof(isb) + options_total_length + 4); + + if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) + return FALSE; + wdh->bytes_dumped += sizeof bh; + + /* write block fixed content */ + isb.interface_id = mand_data->interface_id; + isb.timestamp_high = mand_data->ts_high; + isb.timestamp_low = mand_data->ts_low; + + if (!wtap_dump_file_write(wdh, &isb, sizeof isb, err)) + return FALSE; + wdh->bytes_dumped += sizeof isb; + + if (!wtap_optionblock_write_options(wdh, block, options_total_length, err)) + return FALSE; + + /* write block footer */ + if (!wtap_dump_file_write(wdh, &bh.block_total_length, + sizeof bh.block_total_length, err)) + return FALSE; + wdh->bytes_dumped += sizeof bh.block_total_length; + + return TRUE; } static void isb_copy_mand(wtap_optionblock_t dest_block, wtap_optionblock_t src_block) @@ -478,22 +768,159 @@ static void idb_filter_free(void* data) g_free(filter->if_filter_bpf_bytes); } +static guint32 idb_filter_write_size(wtap_option_type* data) +{ + wtapng_if_descr_filter_t* filter; + guint32 size, pad; + + if (data == NULL) + return 0; + + filter = (wtapng_if_descr_filter_t*)data->customval.data; + if ((filter == NULL) || (filter->if_filter_str == NULL)) + return 0; + + size = (guint32)(strlen(filter->if_filter_str) + 1) & 0xffff; + if ((size % 4)) { + pad = 4 - (size % 4); + } else { + pad = 0; + } + + return pad + size; +} + +static gboolean idb_filter_write(struct wtap_dumper* wdh, wtap_option_type* data, int *err) +{ + wtapng_if_descr_filter_t* filter = (wtapng_if_descr_filter_t*)data->customval.data; + guint32 size, pad; + const guint32 zero_pad = 0; + + size = (guint32)(strlen(filter->if_filter_str) + 1) & 0xffff; + if ((size % 4)) { + pad = 4 - (size % 4); + } else { + pad = 0; + } + + /* Write the zero indicating libpcap filter variant */ + if (!wtap_dump_file_write(wdh, &zero_pad, 1, err)) + return FALSE; + wdh->bytes_dumped += 1; + + /* if_filter_str_len includes the leading byte indicating filter type (libpcap str or BPF code) */ + if (!wtap_dump_file_write(wdh, filter->if_filter_str, size-1, err)) + return FALSE; + wdh->bytes_dumped += size - 1; + + /* write padding (if any) */ + if (pad != 0) { + if (!wtap_dump_file_write(wdh, &zero_pad, pad, err)) + return FALSE; + wdh->bytes_dumped += pad; + } + + return TRUE; +} + static void idb_create(wtap_optionblock_t block) { + static wtap_optblock_reg_t comment_option = {"opt_comment", "Optional comment", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + static wtap_optblock_reg_t name_option = {"name", "Device name", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + static wtap_optblock_reg_t description_option = {"description", "Device description", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + static wtap_optblock_reg_t speed_option = {"speed", "Interface speed (in bps)", WTAP_OPTTYPE_UINT64, wtap_opttype_write_uint64_not0, wtap_opttype_write_data_uint64, {0}, {0}}; + static wtap_optblock_reg_t tsresol_option = {"ts_resolution", "Resolution of timestamps", WTAP_OPTTYPE_UINT8, wtap_opttype_write_uint8_not0, wtap_opttype_write_data_uint8, {0}, {0}}; + static wtap_optblock_reg_t filter_option = {"filter", "Filter string", WTAP_OPTTYPE_CUSTOM, idb_filter_write_size, idb_filter_write, {0}, {0}}; + static wtap_optblock_reg_t os_option = {"os", "Operating System", WTAP_OPTTYPE_STRING, wtap_opttype_write_size_string, wtap_opttype_write_data_string, {0}, {0}}; + static wtap_optblock_reg_t fcslen_option = {"fcslen", "FCS Length", WTAP_OPTTYPE_UINT8, NULL, NULL, {0}, {0}}; + wtapng_if_descr_filter_t default_filter; memset(&default_filter, 0, sizeof(default_filter)); block->mandatory_data = g_new0(wtapng_if_descr_mandatory_t, 1); - block->options = g_array_new(FALSE, FALSE, sizeof(wtap_opttype_t*)); - wtap_optionblock_add_option_string(block, OPT_COMMENT, "opt_comment", "Optional comment", NULL, NULL); - wtap_optionblock_add_option_string(block, OPT_IDB_NAME, "name", "Device name", NULL, NULL); - wtap_optionblock_add_option_string(block, OPT_IDB_DESCR, "description", "Device description", NULL, NULL); - wtap_optionblock_add_option_uint64(block, OPT_IDB_SPEED, "speed", "Interface speed (in bps)", G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF), G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)); - wtap_optionblock_add_option_uint8(block, OPT_IDB_TSRESOL, "ts_resolution", "Resolution of timestamps", 6, 6); - wtap_optionblock_add_option_custom(block, OPT_IDB_FILTER, "filter", "Filter string", &default_filter, &default_filter, sizeof(wtapng_if_descr_filter_t), idb_filter_free); - wtap_optionblock_add_option_string(block, OPT_IDB_OS, "os", "Operating System", NULL, NULL); - wtap_optionblock_add_option_uint8(block, OPT_IDB_FCSLEN, "fcslen", "FCS Length", -1, -1); + /* Set proper values for the union */ + comment_option.option.stringval = NULL; + comment_option.default_val.stringval = NULL; + name_option.option.stringval = NULL; + name_option.default_val.stringval = NULL; + description_option.option.stringval = NULL; + description_option.default_val.stringval = NULL; + speed_option.option.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + speed_option.default_val.uint64val = G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF); + tsresol_option.option.uint8val = 6; + tsresol_option.default_val.uint8val = 6; + filter_option.option.customval.size = sizeof(wtapng_if_descr_filter_t); + filter_option.option.customval.data = &default_filter; + filter_option.option.customval.free_func = idb_filter_free; + filter_option.default_val.customval.size = sizeof(wtapng_if_descr_filter_t); + filter_option.default_val.customval.data = &default_filter; + filter_option.default_val.customval.free_func = idb_filter_free; + os_option.option.stringval = NULL; + os_option.default_val.stringval = NULL; + fcslen_option.option.uint8val = -1; + fcslen_option.default_val.uint8val = -1; + + wtap_optionblock_add_option(block, OPT_COMMENT, &comment_option); + wtap_optionblock_add_option(block, OPT_IDB_NAME, &name_option); + wtap_optionblock_add_option(block, OPT_IDB_DESCR, &description_option); + wtap_optionblock_add_option(block, OPT_IDB_SPEED, &speed_option); + wtap_optionblock_add_option(block, OPT_IDB_TSRESOL, &tsresol_option); + wtap_optionblock_add_option(block, OPT_IDB_FILTER, &filter_option); + wtap_optionblock_add_option(block, OPT_IDB_OS, &os_option); + wtap_optionblock_add_option(block, OPT_IDB_FCSLEN, &fcslen_option); +} + +static gboolean idb_write(struct wtap_dumper *wdh, wtap_optionblock_t block, int *err) +{ + pcapng_block_header_t bh; + pcapng_interface_description_block_t idb; + wtapng_if_descr_mandatory_t* mand_data = (wtapng_if_descr_mandatory_t*)block->mandatory_data; + guint32 options_total_length; + + wtap_debug("write_interface_description_block: encap = %d (%s), snaplen = %d", + mand_data->link_type, + wtap_encap_string(wtap_pcap_encap_to_wtap_encap(mand_data->link_type)), + mand_data->snap_len); + + if (mand_data->link_type == (guint16)-1) { + *err = WTAP_ERR_UNWRITABLE_ENCAP; + return FALSE; + } + + options_total_length = wtap_optionblock_get_option_write_size(block); + if (options_total_length > 0) + { + /* End-of-options tag */ + options_total_length += 4; + } + + /* write block header */ + bh.block_type = BLOCK_TYPE_IDB; + bh.block_total_length = (guint32)(sizeof(bh) + sizeof(idb) + options_total_length + 4); + + if (!wtap_dump_file_write(wdh, &bh, sizeof bh, err)) + return FALSE; + wdh->bytes_dumped += sizeof bh; + + /* write block fixed content */ + idb.linktype = mand_data->link_type; + idb.reserved = 0; + idb.snaplen = mand_data->snap_len; + + if (!wtap_dump_file_write(wdh, &idb, sizeof idb, err)) + return FALSE; + wdh->bytes_dumped += sizeof idb; + + if (!wtap_optionblock_write_options(wdh, block, options_total_length, err)) + return FALSE; + + /* write block footer */ + if (!wtap_dump_file_write(wdh, &bh.block_total_length, + sizeof bh.block_total_length, err)) + return FALSE; + wdh->bytes_dumped += sizeof bh.block_total_length; + return TRUE; } static void idb_free_mand(wtap_optionblock_t block) @@ -542,6 +969,7 @@ void wtap_opttypes_initialize(void) "SHB", /* name */ "Section Header Block", /* description */ shb_create, /* create */ + shb_write, /* write */ NULL, /* free_mand */ shb_copy_mand, /* copy_mand */ }; @@ -550,6 +978,7 @@ void wtap_opttypes_initialize(void) "NRB", /* name */ "Name Resolution Block", /* description */ nrb_create, /* create */ + NULL, /* write */ NULL, /* free_mand */ NULL, /* copy_mand */ }; @@ -558,6 +987,7 @@ void wtap_opttypes_initialize(void) "ISB", /* name */ "Interface Statistics Block", /* description */ isb_create, /* create */ + isb_write, /* write */ NULL, /* free_mand */ isb_copy_mand, /* copy_mand */ }; @@ -566,6 +996,7 @@ void wtap_opttypes_initialize(void) "IDB", /* name */ "Interface Description Block", /* description */ idb_create, /* create */ + idb_write, /* write */ idb_free_mand, /* free_mand */ idb_copy_mand, /* copy_mand */ }; diff --git a/wiretap/wtap_opttypes.h b/wiretap/wtap_opttypes.h index 7d404f221d..1b686a829c 100644 --- a/wiretap/wtap_opttypes.h +++ b/wiretap/wtap_opttypes.h @@ -24,6 +24,9 @@ #include "ws_symbol_export.h" +struct wtap_optionblock; +typedef struct wtap_optionblock *wtap_optionblock_t; + /* Currently supported option blocks */ typedef enum { WTAP_OPTION_BLOCK_IF_DESCR = 0, @@ -57,27 +60,27 @@ struct wtap_opttype_custom wtap_opttype_free_custom_func free_func; }; -typedef struct wtap_opttype { +typedef union { + guint8 uint8val; + guint64 uint64val; + char *stringval; + struct wtap_opttype_custom customval; +} wtap_option_type; + +struct wtap_dumper; + +typedef guint32 (*wtap_opttype_option_write_size)(wtap_option_type* data); /**< does the option have data worth writing (Ex string option != NULL */ +typedef gboolean (*wtap_opttype_option_write)(struct wtap_dumper* wdh, wtap_option_type* data, int *err); /**< does the option have data worth writing (Ex string option != NULL */ + +typedef struct wtap_optblock_reg { const char *name; /**< name of option */ const char *description; /**< human-readable description of option */ - guint number; /**< Option index */ wtap_opttype_e type; /**< type of that option */ - union { - guint8 uint8val; - guint64 uint64val; - char *stringval; - struct wtap_opttype_custom customval; - } option; /**< pointer to variable storing the value */ - union { - guint8 uint8val; - guint64 uint64val; - char *stringval; - struct wtap_opttype_custom customval; - } default_val; /**< the default value of the option */ -} wtap_opttype_t; - -struct wtap_optionblock; -typedef struct wtap_optionblock *wtap_optionblock_t; + wtap_opttype_option_write_size write_size_func; /**< Size of option in file (0 to not write option) */ + wtap_opttype_option_write write_func; /**< write option data to dumper */ + wtap_option_type option; /**< pointer to variable storing the value */ + wtap_option_type default_val; /**< the default value of the option */ +} wtap_optblock_reg_t; /** Initialize option block types. * @@ -111,132 +114,86 @@ WS_DLL_PUBLIC void wtap_optionblock_free(wtap_optionblock_t block); */ WS_DLL_PUBLIC void* wtap_optionblock_get_mandatory_data(wtap_optionblock_t block); -/** Add a string option to the option block +/** Add an option to the option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[in] name Name of option - * @param[in] description Description of option - * @param[in] opt_value Current value of option - * @param[in] default_value Default value of option + * @param[in] option structure explaining it * @return 0 if successful */ -int wtap_optionblock_add_option_string(wtap_optionblock_t block, guint option_id, - const char *name, const char *description, char* opt_value, char* default_value); +int wtap_optionblock_add_option(wtap_optionblock_t block, guint option_id, wtap_optblock_reg_t* option); /** Set string option value to an option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[in] opt_value New value of option + * @param[in] value New value of option * @return 0 if successful */ -WS_DLL_PUBLIC int wtap_optionblock_set_option_string(wtap_optionblock_t block, guint option_id, char* opt_value); +WS_DLL_PUBLIC int wtap_optionblock_set_option_string(wtap_optionblock_t block, guint option_id, char* value); /** Get string option value from an option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[out] opt_value Returned value of option + * @param[out] value Returned value of option * @return 0 if successful */ -WS_DLL_PUBLIC int wtap_optionblock_get_option_string(wtap_optionblock_t block, guint option_id, char** opt_value); - -/** Add UINT64 option to the option block - * - * @param[in] block Block to add option - * @param[in] option_id Identifier value for option - * @param[in] name Name of option - * @param[in] description Description of option - * @param[in] opt_value Current value of option - * @param[in] default_value Default value of option - * @return 0 if successful - */ -int wtap_optionblock_add_option_uint64(wtap_optionblock_t block, guint option_id, - const char *name, const char *description, guint64 opt_value, guint64 default_value); +WS_DLL_PUBLIC int wtap_optionblock_get_option_string(wtap_optionblock_t block, guint option_id, char** value); /** Set UINT64 option value to an option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[in] opt_value New value of option + * @param[in] value New value of option * @return 0 if successful */ -WS_DLL_PUBLIC int wtap_optionblock_set_option_uint64(wtap_optionblock_t block, guint option_id, guint64 opt_value); +WS_DLL_PUBLIC int wtap_optionblock_set_option_uint64(wtap_optionblock_t block, guint option_id, guint64 value); /** Get UINT64 option value from an option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[out] opt_value Returned value of option + * @param[out] value Returned value of option * @return 0 if successful */ -WS_DLL_PUBLIC int wtap_optionblock_get_option_uint64(wtap_optionblock_t block, guint option_id, guint64* opt_value); - -/** Add UINT8 option to the option block - * - * @param[in] block Block to add option - * @param[in] option_id Identifier value for option - * @param[in] name Name of option - * @param[in] description Description of option - * @param[in] opt_value Current value of option - * @param[in] default_value Default value of option - * @return 0 if successful - */ -int wtap_optionblock_add_option_uint8(wtap_optionblock_t block, guint option_id, - const char *name, const char *description, guint8 opt_value, guint8 default_value); +WS_DLL_PUBLIC int wtap_optionblock_get_option_uint64(wtap_optionblock_t block, guint option_id, guint64* value); /** Set UINT8 option value to an option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[in] opt_value New value of option + * @param[in] value New value of option * @return 0 if successful */ -WS_DLL_PUBLIC int wtap_optionblock_set_option_uint8(wtap_optionblock_t block, guint option_id, guint8 opt_value); +WS_DLL_PUBLIC int wtap_optionblock_set_option_uint8(wtap_optionblock_t block, guint option_id, guint8 value); /** Get UINT8 option value from an option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[out] opt_value Returned value of option + * @param[out] value Returned value of option * @return 0 if successful */ -WS_DLL_PUBLIC int wtap_optionblock_get_option_uint8(wtap_optionblock_t block, guint option_id, guint8* opt_value); - -/** Add a "custom" option to the option block - * - * @param[in] block Block to add option - * @param[in] option_id Identifier value for option - * @param[in] name Name of option - * @param[in] description Description of option - * @param[in] opt_value Current value of option - * @param[in] default_value Default value of option - * @param[in] size Size of the option structure - * @param[in] free_func Function to free to the option structure - * @return 0 if successful - */ -int wtap_optionblock_add_option_custom(wtap_optionblock_t block, guint option_id, - const char *name, const char *description, void* opt_value, void* default_value, - guint size, wtap_opttype_free_custom_func free_func); +WS_DLL_PUBLIC int wtap_optionblock_get_option_uint8(wtap_optionblock_t block, guint option_id, guint8* value); /** Set a "custom" option value to an option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[in] opt_value New value of option + * @param[in] value New value of option * @return 0 if successful */ -WS_DLL_PUBLIC int wtap_optionblock_set_option_custom(wtap_optionblock_t block, guint option_id, void* opt_value); +WS_DLL_PUBLIC int wtap_optionblock_set_option_custom(wtap_optionblock_t block, guint option_id, void* value); /** Get a "custom" option value from an option block * * @param[in] block Block to add option * @param[in] option_id Identifier value for option - * @param[out] opt_value Returned value of option + * @param[out] value Returned value of option * @return 0 if successful */ -WS_DLL_PUBLIC int wtap_optionblock_get_option_custom(wtap_optionblock_t block, guint option_id, void** opt_value); +WS_DLL_PUBLIC int wtap_optionblock_get_option_custom(wtap_optionblock_t block, guint option_id, void** value); /** Copy an option block to another. * @@ -248,5 +205,31 @@ WS_DLL_PUBLIC int wtap_optionblock_get_option_custom(wtap_optionblock_t block, g */ void wtap_optionblock_copy_options(wtap_optionblock_t dest_block, wtap_optionblock_t src_block); +/** Write an option block + * + * Will write all mandatory data as well as "valid" options + * + * @param[in] wdh writing assistant + * @param[in] block Block to be written + * @param[in] err Any errors that occurred + * @return TRUE if successful, FALSE will populate err + */ +gboolean wtap_optionblock_write(struct wtap_dumper *wdh, wtap_optionblock_t block, int *err); + +/* Some utility functions for option types */ + +guint32 wtap_opttype_write_size_string(wtap_option_type* data); +gboolean wtap_opttype_write_data_string(struct wtap_dumper* wdh, wtap_option_type* data, int *err); + +/* if option value = 0, write size = 0, otherwise 4 */ +guint32 wtap_opttype_write_uint8_not0(wtap_option_type* data); +gboolean wtap_opttype_write_data_uint8(struct wtap_dumper* wdh, wtap_option_type* data, int *err); + +/* if option value = 0, write size = 0, otherwise 8 */ +guint32 wtap_opttype_write_uint64_not0(wtap_option_type* data); +/* if option value = -1 (0xFFFFFFFFFFFFFFFF), write size = 0, otherwise 8 */ +guint32 wtap_opttype_write_uint64_not_minus1(wtap_option_type* data); +gboolean wtap_opttype_write_data_uint64(struct wtap_dumper* wdh, wtap_option_type* data, int *err); + #endif /* WTAP_OPT_TYPES_H */