diff --git a/acinclude.m4 b/acinclude.m4 index 44545f6c1e..c76d2bf7d7 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -412,7 +412,7 @@ install a newer version of the header file.]) AC_DEFINE(CAN_SET_CAPTURE_BUFFER_SIZE, 1, [Define to 1 if the capture buffer size can be set.]) ]) - AC_CHECK_FUNCS(bpf_image pcap_set_tstamp_precision) + AC_CHECK_FUNCS(bpf_image pcap_set_tstamp_precision pcap_set_tstamp_type) fi AC_WIRESHARK_POP_FLAGS diff --git a/capchild/capture_ifinfo.c b/capchild/capture_ifinfo.c index e3773f512b..d158cabe81 100644 --- a/capchild/capture_ifinfo.c +++ b/capchild/capture_ifinfo.c @@ -228,11 +228,10 @@ capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode, char **err_str, void (*update_cb)(void)) { if_capabilities_t *caps; - GList *linktype_list = NULL; + GList *linktype_list = NULL, *timestamp_list = NULL; int err, i; gchar *data, *primary_msg, *secondary_msg; - gchar **raw_list, **lt_parts; - data_link_info_t *data_link_info; + gchar **raw_list; g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities ..."); @@ -309,11 +308,12 @@ capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode, } /* - * The rest are link-layer types. + * The following are link-layer types. */ - for (i = 1; raw_list[i] != NULL; i++) { + for (i = 1; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) { + data_link_info_t *data_link_info; /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */ - lt_parts = g_strsplit(raw_list[i], "\t", 3); + char **lt_parts = g_strsplit(raw_list[i], "\t", 3); if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) { g_strfreev(lt_parts); continue; @@ -330,6 +330,25 @@ capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode, linktype_list = g_list_append(linktype_list, data_link_info); } + + if (raw_list[i]) { /* Oh, timestamp types! */ + for (i++; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) { + timestamp_info_t *timestamp_info; + char **tt_parts = g_strsplit(raw_list[i], "\t", 2); + if (tt_parts[0] == NULL || tt_parts[1] == NULL) { + g_strfreev(tt_parts); + continue; + } + + timestamp_info = g_new(timestamp_info_t,1); + timestamp_info->name = g_strdup(tt_parts[0]); + timestamp_info->description = g_strdup(tt_parts[1]); + g_strfreev(tt_parts); + + timestamp_list = g_list_append(timestamp_list, timestamp_info); + } + } + g_strfreev(raw_list); /* Check to see if we built a list */ @@ -340,7 +359,11 @@ capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode, g_free(caps); return NULL; } + caps->data_link_types = linktype_list; + /* Might be NULL. Not all systems report timestamp types */ + caps->timestamp_types = timestamp_list; + return caps; } diff --git a/capchild/capture_sync.c b/capchild/capture_sync.c index 96911bddae..9f3d0ca0b9 100644 --- a/capchild/capture_sync.c +++ b/capchild/capture_sync.c @@ -412,6 +412,10 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, inf argv = sync_pipe_add_arg(argv, &argc, ssampling); } #endif + if (interface_opts.timestamp_type) { + argv = sync_pipe_add_arg(argv, &argc, "--time-stamp-type"); + argv = sync_pipe_add_arg(argv, &argc, interface_opts.timestamp_type); + } } /* dumpcap should be running in capture child mode (hidden feature) */ @@ -1302,6 +1306,7 @@ sync_if_capabilities_open(const gchar *ifname, gboolean monitor_mode, const gcha argv = sync_pipe_add_arg(argv, &argc, "-i"); argv = sync_pipe_add_arg(argv, &argc, ifname); argv = sync_pipe_add_arg(argv, &argc, "-L"); + argv = sync_pipe_add_arg(argv, &argc, "--list-time-stamp-types"); if (monitor_mode) argv = sync_pipe_add_arg(argv, &argc, "-I"); if (auth) { diff --git a/capture_opts.c b/capture_opts.c index 92175ff78b..a5470904c2 100644 --- a/capture_opts.c +++ b/capture_opts.c @@ -90,6 +90,7 @@ capture_opts_init(capture_options *capture_opts) capture_opts->default_options.sampling_method = CAPTURE_SAMP_NONE; capture_opts->default_options.sampling_param = 0; #endif + capture_opts->default_options.timestamp_type = NULL; capture_opts->saving_to_file = FALSE; capture_opts->save_file = NULL; capture_opts->group_read_access = FALSE; @@ -193,6 +194,7 @@ capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_optio g_log(log_domain, log_level, "Sampling meth.[%02d] : %d", i, interface_opts.sampling_method); g_log(log_domain, log_level, "Sampling param.[%02d] : %d", i, interface_opts.sampling_param); #endif + g_log(log_domain, log_level, "Timestamp type [%02d] : %s", i, interface_opts.timestamp_type); } g_log(log_domain, log_level, "Interface name[df] : %s", capture_opts->default_options.name ? capture_opts->default_options.name : "(unspecified)"); g_log(log_domain, log_level, "Interface Descr[df] : %s", capture_opts->default_options.descr ? capture_opts->default_options.descr : "(unspecified)"); @@ -233,6 +235,7 @@ capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_optio g_log(log_domain, log_level, "Sampling meth. [df] : %d", capture_opts->default_options.sampling_method); g_log(log_domain, log_level, "Sampling param.[df] : %d", capture_opts->default_options.sampling_param); #endif + g_log(log_domain, log_level, "Timestamp type [df] : %s", capture_opts->default_options.timestamp_type ? capture_opts->default_options.timestamp_type : "(unspecified)"); g_log(log_domain, log_level, "SavingToFile : %u", capture_opts->saving_to_file); g_log(log_domain, log_level, "SaveFile : %s", (capture_opts->save_file) ? capture_opts->save_file : ""); g_log(log_domain, log_level, "GroupReadAccess : %u", capture_opts->group_read_access); @@ -732,6 +735,7 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str interface_opts.sampling_method = capture_opts->default_options.sampling_method; interface_opts.sampling_param = capture_opts->default_options.sampling_param; #endif + interface_opts.timestamp_type = capture_opts->default_options.timestamp_type; g_array_append_val(capture_opts->ifaces, interface_opts); @@ -800,6 +804,18 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_ case 'H': /* Hide capture info dialog box */ capture_opts->show_info = FALSE; break; + case LONGOPT_SET_TSTAMP_TYPE: /* Set capture time stamp type */ + if (capture_opts->ifaces->len > 0) { + interface_options interface_opts; + + interface_opts = g_array_index(capture_opts->ifaces, interface_options, capture_opts->ifaces->len - 1); + capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, capture_opts->ifaces->len - 1); + interface_opts.timestamp_type = g_strdup(optarg_str_p); + g_array_append_val(capture_opts->ifaces, interface_opts); + } else { + capture_opts->default_options.timestamp_type = g_strdup(optarg_str_p); + } + break; case 'i': /* Use interface x */ status = capture_opts_add_iface_opt(capture_opts, optarg_str_p); if (status != 0) { @@ -939,26 +955,40 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg_ } void -capture_opts_print_if_capabilities(if_capabilities_t *caps, char *name, - gboolean monitor_mode) +capture_opts_print_if_capabilities(if_capabilities_t *caps, char *name, int queries) { - GList *lt_entry; - data_link_info_t *data_link_info; + GList *lt_entry, *ts_entry; - if (caps->can_set_rfmon) - printf("Data link types of interface %s when %sin monitor mode (use option -y to set):\n", - name, monitor_mode ? "" : "not "); - else - printf("Data link types of interface %s (use option -y to set):\n", name); - for (lt_entry = caps->data_link_types; lt_entry != NULL; - lt_entry = g_list_next(lt_entry)) { - data_link_info = (data_link_info_t *)lt_entry->data; - printf(" %s", data_link_info->name); - if (data_link_info->description != NULL) - printf(" (%s)", data_link_info->description); + if (queries & CAPS_QUERY_LINK_TYPES) { + if (caps->can_set_rfmon) + printf("Data link types of interface %s when %sin monitor mode (use option -y to set):\n", + name, queries & CAPS_MONITOR_MODE ? "" : "not "); else - printf(" (not supported)"); - printf("\n"); + printf("Data link types of interface %s (use option -y to set):\n", name); + for (lt_entry = caps->data_link_types; lt_entry != NULL; + lt_entry = g_list_next(lt_entry)) { + data_link_info_t *data_link_info = (data_link_info_t *)lt_entry->data; + printf(" %s", data_link_info->name); + if (data_link_info->description != NULL) + printf(" (%s)", data_link_info->description); + else + printf(" (not supported)"); + printf("\n"); + } + } + + if (queries & CAPS_QUERY_TIMESTAMP_TYPES) { + printf("Timestamp types of the interface (use option --time-stamp-type to set):\n"); + for (ts_entry = caps->timestamp_types; ts_entry != NULL; + ts_entry = g_list_next(ts_entry)) { + timestamp_info_t *timestamp = (timestamp_info_t *)ts_entry->data; + printf(" %s", timestamp->name); + if (timestamp->description != NULL) + printf(" (%s)", timestamp->description); + else + printf(" (none)"); + printf("\n"); + } } } diff --git a/capture_opts.h b/capture_opts.h index 2fc04a339c..c3b830e3b3 100644 --- a/capture_opts.h +++ b/capture_opts.h @@ -60,7 +60,9 @@ extern "C" { * In short: we must not use 1 here, which is another reason to use * values outside the range of ASCII graphic characters. */ -#define LONGOPT_NUM_CAP_COMMENT 128 +#define LONGOPT_NUM_CAP_COMMENT 128 +#define LONGOPT_LIST_TSTAMP_TYPES 129 +#define LONGOPT_SET_TSTAMP_TYPE 130 /* * Options for capturing common to all capturing programs. @@ -89,17 +91,20 @@ extern "C" { #endif #define LONGOPT_CAPTURE_COMMON \ - {"capture-comment", required_argument, NULL, LONGOPT_NUM_CAP_COMMENT}, \ - {"autostop", required_argument, NULL, 'a'}, \ - {"ring-buffer", required_argument, NULL, 'b'}, \ + {"capture-comment", required_argument, NULL, LONGOPT_NUM_CAP_COMMENT}, \ + {"autostop", required_argument, NULL, 'a'}, \ + {"ring-buffer", required_argument, NULL, 'b'}, \ LONGOPT_BUFFER_SIZE \ - {"list-interfaces", no_argument, NULL, 'D'}, \ - {"interface", required_argument, NULL, 'i'}, \ + {"list-interfaces", no_argument, NULL, 'D'}, \ + {"interface", required_argument, NULL, 'i'}, \ LONGOPT_MONITOR_MODE \ - {"list-data-link-types", no_argument, NULL, 'L'}, \ - {"no-promiscuous-mode", no_argument, NULL, 'p'}, \ - {"snapshot-length", required_argument, NULL, 's'}, \ - {"linktype", required_argument, NULL, 'y'}, \ + {"list-data-link-types", no_argument, NULL, 'L'}, \ + {"no-promiscuous-mode", no_argument, NULL, 'p'}, \ + {"snapshot-length", required_argument, NULL, 's'}, \ + {"linktype", required_argument, NULL, 'y'}, \ + {"list-time-stamp-types", no_argument, NULL, LONGOPT_LIST_TSTAMP_TYPES}, \ + {"time-stamp-type", required_argument, NULL, LONGOPT_SET_TSTAMP_TYPE}, + #define OPTSTRING_CAPTURE_COMMON \ "a:" OPTSTRING_A "b:" OPTSTRING_B "c:Df:i:" OPTSTRING_I "Lps:y:" @@ -248,6 +253,9 @@ typedef struct interface_options_tag { capture_sampling sampling_method; int sampling_param; #endif + gchar *timestamp_type; /* requested timestamp as string */ + int timestamp_type_id; /* Timestamp type to pass to pcap_set_tstamp_type. + only valid if timestamp_type != NULL */ } interface_options; /** Capture options coming from user interface */ @@ -342,10 +350,15 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, extern void capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_options *capture_opts); +enum caps_query { + CAPS_MONITOR_MODE = 0x1, + CAPS_QUERY_LINK_TYPES = 0x2, + CAPS_QUERY_TIMESTAMP_TYPES = 0x4 +}; + /* print interface capabilities, including link layer types */ extern void -capture_opts_print_if_capabilities(if_capabilities_t *caps, char *name, - gboolean monitor_mode); +capture_opts_print_if_capabilities(if_capabilities_t *caps, char *name, int queries); /* print list of interfaces */ extern void diff --git a/caputils/capture-pcap-util.c b/caputils/capture-pcap-util.c index 4da5579e3d..07d7db06f7 100644 --- a/caputils/capture-pcap-util.c +++ b/caputils/capture-pcap-util.c @@ -668,11 +668,24 @@ free_linktype_cb(gpointer data, gpointer user_data _U_) g_free(linktype_info); } +static void +free_timestamp_cb(gpointer data, gpointer user_data _U_) +{ + /* timestamp_info_t's contents are immutable and in static memory, + * so we only need to free the struct itself + */ + g_free(data); +} + void free_if_capabilities(if_capabilities_t *caps) { g_list_foreach(caps->data_link_types, free_linktype_cb, NULL); g_list_free(caps->data_link_types); + + g_list_foreach(caps->timestamp_types, free_timestamp_cb, NULL); + g_list_free(caps->timestamp_types); + g_free(caps); } @@ -861,10 +874,7 @@ create_data_link_info(int dlt) else data_link_info->name = g_strdup_printf("DLT %d", dlt); text = pcap_datalink_val_to_description(dlt); - if (text != NULL) - data_link_info->description = g_strdup(text); - else - data_link_info->description = NULL; + data_link_info->description = g_strdup(text); return data_link_info; } @@ -960,6 +970,34 @@ get_data_link_types(pcap_t *pch, interface_options *interface_opts, return data_link_types; } +/* Get supported timestamp types for a libpcap device. */ +static GList* +get_pcap_timestamp_types(pcap_t *pch _U_, char **err_str _U_) +{ + GList *list = NULL; +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE + int *types; + int ntypes = pcap_list_tstamp_types(pch, &types); + + if (err_str) + *err_str = ntypes < 0 ? pcap_geterr(pch) : NULL; + + if (ntypes <= 0) + return NULL; + + while (ntypes--) { + timestamp_info_t *info = (timestamp_info_t *)g_malloc(sizeof *info); + info->name = pcap_tstamp_type_val_to_name(types[ntypes]); + info->description = pcap_tstamp_type_val_to_description(types[ntypes]); + list = g_list_prepend(list, info); + } + + pcap_free_tstamp_types(types); +#endif + return list; +} + + #ifdef HAVE_PCAP_CREATE #ifdef HAVE_BONDING static gboolean @@ -1079,6 +1117,8 @@ get_if_capabilities_pcap_create(interface_options *interface_opts, return NULL; } + caps->timestamp_types = get_pcap_timestamp_types(pch, NULL); + pcap_close(pch); if (err_str != NULL) @@ -1088,7 +1128,7 @@ get_if_capabilities_pcap_create(interface_options *interface_opts, pcap_t * open_capture_device_pcap_create(capture_options *capture_opts -#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION +#if defined(HAVE_PCAP_SET_TSTAMP_PRECISION) || defined (HAVE_PCAP_SET_TSTAMP_TYPE) , #else _U_, @@ -1141,6 +1181,18 @@ open_capture_device_pcap_create(capture_options *capture_opts request_high_resolution_timestamp(pcap_h); #endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */ +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE + if (interface_opts->timestamp_type) { + err = pcap_set_tstamp_type(pcap_h, interface_opts->timestamp_type_id); + if (err == PCAP_ERROR) { + g_strlcpy(*open_err_str, pcap_geterr(pcap_h), + sizeof *open_err_str); + pcap_close(pcap_h); + return NULL; + } + } +#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */ + g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "buffersize %d.", interface_opts->buffer_size); if (interface_opts->buffer_size != 0) @@ -1195,6 +1247,8 @@ get_if_capabilities_pcap_open_live(interface_options *interface_opts, return NULL; } + caps->timestamp_types = get_pcap_timestamp_types(pch, NULL); + pcap_close(pch); if (err_str != NULL) @@ -1295,8 +1349,8 @@ get_if_capabilities(interface_options *interface_opts, char **err_str) caps->data_link_types = NULL; deflt = get_pcap_datalink(pch, interface_opts->name); data_link_info = create_data_link_info(deflt); - caps->data_link_types = g_list_append(caps->data_link_types, - data_link_info); + caps->data_link_types = g_list_append(caps->data_link_types, data_link_info); + caps->timestamp_types = get_pcap_timestamp_types(pch, NULL); pcap_close(pch); if (err_str != NULL) diff --git a/caputils/capture_ifinfo.h b/caputils/capture_ifinfo.h index 16ae28fd51..48c54feec8 100644 --- a/caputils/capture_ifinfo.h +++ b/caputils/capture_ifinfo.h @@ -99,6 +99,7 @@ void free_interface_list(GList *if_list); typedef struct { gboolean can_set_rfmon; /* TRUE if can be put into monitor mode */ GList *data_link_types; /* GList of data_link_info_t's */ + GList *timestamp_types; /* GList of timestamp_info_t's */ } if_capabilities_t; /* @@ -110,6 +111,14 @@ typedef struct { char *description; /* descriptive name from wiretap e.g. "Ethernet", NULL if unknown */ } data_link_info_t; +/* + * Information about timestamp types. + */ +typedef struct { + const char *name; /* e.g. "adapter_unsynced" */ + const char *description; /* description from libpcap e.g. "Adapter, not synced with system time" */ +} timestamp_info_t; + /** * Fetch the linktype list for the specified interface from a child process. */ diff --git a/cmake/modules/FindPCAP.cmake b/cmake/modules/FindPCAP.cmake index 508d46b3a7..d8812c94c6 100644 --- a/cmake/modules/FindPCAP.cmake +++ b/cmake/modules/FindPCAP.cmake @@ -85,6 +85,7 @@ if( PCAP_FOUND ) check_function_exists( "bpf_image" HAVE_BPF_IMAGE ) check_function_exists( "pcap_setsampling" HAVE_PCAP_SETSAMPLING ) check_function_exists( "pcap_set_tstamp_precision" HAVE_PCAP_SET_TSTAMP_PRECISION ) + check_function_exists( "pcap_set_tstamp_type" HAVE_PCAP_SET_TSTAMP_TYPE ) # Remote pcap checks check_function_exists( "pcap_open" HAVE_PCAP_OPEN ) if( HAVE_PCAP_OPEN ) diff --git a/cmakeconfig.h.in b/cmakeconfig.h.in index 5437207981..2b4048a08d 100644 --- a/cmakeconfig.h.in +++ b/cmakeconfig.h.in @@ -278,6 +278,9 @@ /* Define to 1 if you have the `pcap_set_tstamp_precision' function. */ #cmakedefine HAVE_PCAP_SET_TSTAMP_PRECISION 1 +/* Define to 1 if you have the `pcap_set_tstamp_type' function. */ +#cmakedefine HAVE_PCAP_SET_TSTAMP_TYPE 1 + /* Define to 1 if you have the popcount function. */ #cmakedefine HAVE_POPCOUNT 1 diff --git a/doc/dumpcap.pod b/doc/dumpcap.pod index 1c76aa8fc2..e1e816bc4f 100644 --- a/doc/dumpcap.pod +++ b/doc/dumpcap.pod @@ -32,6 +32,8 @@ S<[ B<-v> ]> S<[ B<-w> EoutfileE ]> S<[ B<-y> Ecapture link typeE ]> S<[ B<--capture-comment> EcommentE ]> +S<[ B<--list-time-stamp-types> ]> +S<[ B<--time-stamp-type> EtypeE ]> =head1 DESCRIPTION @@ -254,7 +256,8 @@ link types can be used for the B<-y> option. =item -M -When used with B<-D>, B<-L> or B<-S>, print machine-readable output. +When used with B<-D>, B<-L>, B<-S> or B<--list-time-stamp-types> print +machine-readable output. The machine-readable output is intended to be read by B and B; its format is subject to change from release to release. @@ -352,6 +355,15 @@ This option is only available if we output the captured packets to a single file in pcap-ng format. Only one capture comment may be set per output file. +=item --list-time-stamp-types + +List time stamp types supported for the interface. If no time stamp type can be +set, no time stamp types are listed. + +=item --time-stamp-type EtypeE + +Change the interface's timestamp method. + =back =head1 CAPTURE FILTER SYNTAX diff --git a/doc/tshark.pod b/doc/tshark.pod index 664851bafe..185409468d 100644 --- a/doc/tshark.pod +++ b/doc/tshark.pod @@ -54,6 +54,8 @@ S<[ B<-Y> EdisplaY filterE ]> S<[ B<-M> Eauto session resetE ]> S<[ B<-z> EstatisticsE ]> S<[ B<--capture-comment> EcommentE ]> +S<[ B<--list-time-stamp-types> ]> +S<[ B<--time-stamp-type> EtypeE ]> S<[ B<--color> ]> S<[ B<--no-duplicate-keys> ]> S<[ B<--export-objects> EprotocolE,EdestdirE ]> @@ -1622,6 +1624,15 @@ Add a capture comment to the output file. This option is only available if a new output file in pcapng format is created. Only one capture comment may be set per output file. +=item --list-time-stamp-types + +List time stamp types supported for the interface. If no time stamp type can be +set, no time stamp types are listed. + +=item --time-stamp-type EtypeE + +Change the interface's timestamp method. + =item --color Enable coloring of packets according to standard Wireshark color filters. This diff --git a/doc/wireshark.pod.template b/doc/wireshark.pod.template index d89bf546fc..09fb6feaa2 100644 --- a/doc/wireshark.pod.template +++ b/doc/wireshark.pod.template @@ -53,6 +53,8 @@ S<[ B<--enable-protocol> Eproto_nameE ]> S<[ B<--disable-protocol> Eproto_nameE ]> S<[ B<--enable-heuristic> Eshort_nameE ]> S<[ B<--disable-heuristic> Eshort_nameE ]> +S<[ B<--list-time-stamp-types> ]> +S<[ B<--time-stamp-type> EtypeE ]> S<[ EinfileE ]> =head1 DESCRIPTION @@ -987,6 +989,15 @@ Enable dissection of heuristic protocol. Disable dissection of heuristic protocol. +=item --list-time-stamp-types + +List time stamp types supported for the interface. If no time stamp type can be +set, no time stamp types are listed. + +=item --time-stamp-type EtypeE + +Change the interface's timestamp method. + =back =head1 INTERFACE diff --git a/docbook/release-notes.asciidoc b/docbook/release-notes.asciidoc index 6bfff65a67..33511794e0 100644 --- a/docbook/release-notes.asciidoc +++ b/docbook/release-notes.asciidoc @@ -41,6 +41,7 @@ since version 2.4.0: * File load time in Status Bar is now disabled by default and can be enabled in Preferences -> Appearance -> Layout -> Show file load time. * Support for G.729 codec in the RTP Player (via the bcg729 library). +* Support for hardware-timestamping of packets //=== Removed Dissectors diff --git a/docbook/wsug_src/WSUG_app_tools.asciidoc b/docbook/wsug_src/WSUG_app_tools.asciidoc index 87c88559f0..e05b033ecf 100644 --- a/docbook/wsug_src/WSUG_app_tools.asciidoc +++ b/docbook/wsug_src/WSUG_app_tools.asciidoc @@ -42,8 +42,10 @@ Capture interface: -I capture in monitor mode, if available -B size of kernel buffer (def: 2MB) -y link layer type (def: first appropriate) + --time-stamp-type timestamp method for interface -D print list of interfaces and exit -L print list of link-layer types of iface and exit + --list-time-stamp-types print list of timestamp types for iface and exit Capture stop conditions: -c stop after n packets (def: infinite) @@ -185,8 +187,10 @@ Capture interface: -I capture in monitor mode, if available -B size of kernel buffer in MiB (def: 2MiB) -y link layer type (def: first appropriate) + --time-stamp-type timestamp method for interface -D print list of interfaces and exit -L print list of link-layer types of iface and exit + --list-time-stamp-types print list of timestamp types for iface and exit -d print generated BPF code for capture filter -k set channel on wifi interface ,[] -S print statistics for each interface once per second diff --git a/docbook/wsug_src/WSUG_chapter_customize.asciidoc b/docbook/wsug_src/WSUG_chapter_customize.asciidoc index 1f797bd7db..618303529a 100644 --- a/docbook/wsug_src/WSUG_chapter_customize.asciidoc +++ b/docbook/wsug_src/WSUG_chapter_customize.asciidoc @@ -56,8 +56,10 @@ Capture interface: -I capture in monitor mode, if available -B size of kernel buffer (def: 2MB) -y link layer type (def: first appropriate) + --time-stamp-type timestamp method for interface -D print list of interfaces and exit -L print list of link-layer types of iface and exit + --list-time-stamp-types print list of timestamp types for iface and exit Capture stop conditions: -c stop after n packets (def: infinite) @@ -273,6 +275,10 @@ updated automatically as packets arrive during a capture ( as specified by the List the data link types supported by the interface and exit. +--list-time-stamp-types:: + +List timestamp types configurable for the iface and exit + -m :: This option sets the name of the font used for most text displayed by Wireshark. @@ -420,10 +426,16 @@ This option sets the name of the file to be used to save captured packets. -y :: -If a capture is started from the command line with -k, set the data -link type to use while capturing packets. The values reported by -L +If a capture is started from the command line with `-k`, set the data +link type to use while capturing packets. The values reported by `-L` are the values that can be used. +--time-stamp-type :: + +If a capture is started from the command line with `-k`, set the data +link type to use while capturing packets. The values reported by +`--list-time-stamp-types` are the values that can be used. + -X :: Specify an option to be passed to a TShark module. The eXtension option is in diff --git a/dumpcap.c b/dumpcap.c index cc248ff781..14c96e6fb9 100644 --- a/dumpcap.c +++ b/dumpcap.c @@ -493,8 +493,10 @@ print_usage(FILE *output) fprintf(output, " -B size of kernel buffer in MiB (def: %dMiB)\n", DEFAULT_CAPTURE_BUFFER_SIZE); #endif fprintf(output, " -y link layer type (def: first appropriate)\n"); + fprintf(output, " --time-stamp-type timestamp method for interface\n"); fprintf(output, " -D print list of interfaces and exit\n"); fprintf(output, " -L print list of link-layer types of iface and exit\n"); + fprintf(output, " --list-time-stamp-types print list of timestamp types for iface and exit\n"); #ifdef HAVE_BPF_IMAGE fprintf(output, " -d print generated BPF code for capture filter\n"); #endif @@ -906,10 +908,9 @@ print_machine_readable_interfaces(GList *if_list) * you MUST update capture_ifinfo.c:capture_get_if_capabilities() accordingly! */ static void -print_machine_readable_if_capabilities(if_capabilities_t *caps) +print_machine_readable_if_capabilities(if_capabilities_t *caps, int queries) { - GList *lt_entry; - data_link_info_t *data_link_info; + GList *lt_entry, *ts_entry; const gchar *desc_str; if (capture_child) { @@ -917,19 +918,33 @@ print_machine_readable_if_capabilities(if_capabilities_t *caps) pipe_write_block(2, SP_SUCCESS, NULL); } - if (caps->can_set_rfmon) - printf("1\n"); - else - printf("0\n"); - for (lt_entry = caps->data_link_types; lt_entry != NULL; - lt_entry = g_list_next(lt_entry)) { - data_link_info = (data_link_info_t *)lt_entry->data; - if (data_link_info->description != NULL) - desc_str = data_link_info->description; - else - desc_str = "(not supported)"; - printf("%d\t%s\t%s\n", data_link_info->dlt, data_link_info->name, - desc_str); + if (queries & CAPS_QUERY_LINK_TYPES) { + if (caps->can_set_rfmon) + printf("1\n"); + else + printf("0\n"); + for (lt_entry = caps->data_link_types; lt_entry != NULL; + lt_entry = g_list_next(lt_entry)) { + data_link_info_t *data_link_info = (data_link_info_t *)lt_entry->data; + if (data_link_info->description != NULL) + desc_str = data_link_info->description; + else + desc_str = "(not supported)"; + printf("%d\t%s\t%s\n", data_link_info->dlt, data_link_info->name, + desc_str); + } + } + printf("\n"); + if (queries & CAPS_QUERY_TIMESTAMP_TYPES) { + for (ts_entry = caps->timestamp_types; ts_entry != NULL; + ts_entry = g_list_next(ts_entry)) { + timestamp_info_t *timestamp = (timestamp_info_t *)ts_entry->data; + if (timestamp->description != NULL) + desc_str = timestamp->description; + else + desc_str = "(none)"; + printf("%s\t%s\n", timestamp->name, desc_str); + } } } @@ -3888,7 +3903,7 @@ main(int argc, char *argv[]) struct pcap_stat stats; GLogLevelFlags log_flags; gboolean list_interfaces = FALSE; - gboolean list_link_layer_types = FALSE; + int caps_queries = 0; #ifdef HAVE_BPF_IMAGE gboolean print_bpf_code = FALSE; #endif @@ -4241,6 +4256,7 @@ main(int argc, char *argv[]) case 'f': /* capture filter */ case 'g': /* enable group read access on file(s) */ case 'i': /* Use interface x */ + case LONGOPT_SET_TSTAMP_TYPE: /* Set capture timestamp type */ case 'n': /* Use pcapng format */ case 'p': /* Don't capture in promiscuous mode */ case 'P': /* Use pcap format */ @@ -4306,11 +4322,14 @@ main(int argc, char *argv[]) } break; case 'L': /* Print list of link-layer types and exit */ - if (!list_link_layer_types) { - list_link_layer_types = TRUE; + if (!(caps_queries & CAPS_QUERY_LINK_TYPES)) { + caps_queries |= CAPS_QUERY_LINK_TYPES; run_once_args++; } break; + case LONGOPT_LIST_TSTAMP_TYPES: + caps_queries |= CAPS_QUERY_TIMESTAMP_TYPES; + break; #ifdef HAVE_BPF_IMAGE case 'd': /* Print BPF code for capture filter and exit */ if (!print_bpf_code) { @@ -4387,9 +4406,9 @@ main(int argc, char *argv[]) if (run_once_args > 1) { #ifdef HAVE_BPF_IMAGE - cmdarg_err("Only one of -D, -L, -d, -k, or -S may be supplied."); + cmdarg_err("Only one of -D, -L, -d, -k or -S may be supplied."); #else - cmdarg_err("Only one of -D, -L, -k, or -S may be supplied."); + cmdarg_err("Only one of -D, -L, -k or -S may be supplied."); #endif exit_main(1); } else if (run_once_args == 1) { @@ -4452,7 +4471,7 @@ main(int argc, char *argv[]) int err; gchar *err_str; - if_list = capture_interface_list(&err, &err_str,NULL); + if_list = capture_interface_list(&err, &err_str, NULL); if (if_list == NULL) { if (err == 0) { /* @@ -4512,13 +4531,14 @@ main(int argc, char *argv[]) exit_main(status); } - if (list_link_layer_types) { - /* Get the list of link-layer types for the capture device. */ + if (caps_queries) { + /* Get the list of link-layer and/or timestamp types for the capture device. */ if_capabilities_t *caps; gchar *err_str; guint ii; for (ii = 0; ii < global_capture_opts.ifaces->len; ii++) { + int if_caps_queries = caps_queries; interface_options interface_opts; interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, ii); @@ -4531,22 +4551,40 @@ main(int argc, char *argv[]) g_free(err_str); exit_main(2); } - if (caps->data_link_types == NULL) { + if ((if_caps_queries & CAPS_QUERY_LINK_TYPES) && caps->data_link_types == NULL) { cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts.name); exit_main(2); - } + } /* No timestamp types is no big deal. So we will just ignore it */ + + if (interface_opts.monitor_mode) + if_caps_queries |= CAPS_MONITOR_MODE; + if (machine_readable) /* tab-separated values to stdout */ - /* XXX: We need to change the format and adopt consumers */ - print_machine_readable_if_capabilities(caps); + /* XXX: We need to change the format and adapt consumers */ + print_machine_readable_if_capabilities(caps, if_caps_queries); else /* XXX: We might want to print also the interface name */ - capture_opts_print_if_capabilities(caps, interface_opts.name, - interface_opts.monitor_mode); + capture_opts_print_if_capabilities(caps, interface_opts.name, if_caps_queries); free_if_capabilities(caps); } exit_main(0); } +#ifdef HAVE_PCAP_SET_TSTAMP_TYPE + for (j = 0; j < global_capture_opts.ifaces->len; j++) { + interface_options *interface_opts; + + interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, j); + if (interface_opts->timestamp_type) { + interface_opts->timestamp_type_id = pcap_tstamp_type_name_to_val(interface_opts->timestamp_type); + if (interface_opts->timestamp_type_id < 0) { + cmdarg_err("Invalid argument to option: --time-stamp-type=%s", interface_opts->timestamp_type); + exit_main(1); + } + } + } +#endif + /* We're supposed to do a capture, or print the BPF code for a filter. */ /* Let the user know what interfaces were chosen. */ diff --git a/extcap.c b/extcap.c index 5e83813e5a..9bb36c178b 100644 --- a/extcap.c +++ b/extcap.c @@ -383,6 +383,7 @@ static gboolean cb_dlt(extcap_callback_info_t cb_info) */ caps = (if_capabilities_t *) g_malloc(sizeof * caps); caps->can_set_rfmon = FALSE; + caps->timestamp_types = NULL; while (dlts) { diff --git a/tshark.c b/tshark.c index 5c44d64e27..97b78b5a58 100644 --- a/tshark.c +++ b/tshark.c @@ -148,6 +148,7 @@ #define INVALID_CAPABILITY 2 #define INVALID_TAP 2 #define INVALID_DATA_LINK 2 +#define INVALID_TIMESTAMP_TYPE 2 #define INVALID_CAPTURE 2 #define INIT_FAILED 2 @@ -353,8 +354,10 @@ print_usage(FILE *output) fprintf(output, " -B size of kernel buffer (def: %dMB)\n", DEFAULT_CAPTURE_BUFFER_SIZE); #endif fprintf(output, " -y link layer type (def: first appropriate)\n"); + fprintf(output, " --time-stamp-type timestamp method for interface\n"); fprintf(output, " -D print list of interfaces and exit\n"); fprintf(output, " -L print list of link-layer types of iface and exit\n"); + fprintf(output, " --list-time-stamp-types print list of timestamp types for iface and exit\n"); fprintf(output, "\n"); fprintf(output, "Capture stop conditions:\n"); fprintf(output, " -c stop after n packets (def: infinite)\n"); @@ -686,7 +689,7 @@ main(int argc, char *argv[]) volatile gboolean success; volatile int exit_status = EXIT_SUCCESS; #ifdef HAVE_LIBPCAP - gboolean list_link_layer_types = FALSE; + int caps_queries = 0; gboolean start_capture = FALSE; GList *if_list; gchar *err_str; @@ -1082,6 +1085,7 @@ main(int argc, char *argv[]) case 'f': /* capture filter */ case 'g': /* enable group read access on file(s) */ case 'i': /* Use interface x */ + case LONGOPT_SET_TSTAMP_TYPE: /* Set capture timestamp type */ case 'p': /* Don't capture in promiscuous mode */ #ifdef HAVE_PCAP_REMOTE case 'A': /* Authentication */ @@ -1226,7 +1230,15 @@ main(int argc, char *argv[]) break; case 'L': /* Print list of link-layer types and exit */ #ifdef HAVE_LIBPCAP - list_link_layer_types = TRUE; + caps_queries |= CAPS_QUERY_LINK_TYPES; +#else + capture_option_specified = TRUE; + arg_error = TRUE; +#endif + break; + case LONGOPT_LIST_TSTAMP_TYPES: /* List possible timestamp types */ +#ifdef HAVE_LIBPCAP + caps_queries |= CAPS_QUERY_TIMESTAMP_TYPES; #else capture_option_specified = TRUE; arg_error = TRUE; @@ -1601,12 +1613,13 @@ main(int argc, char *argv[]) } #ifdef HAVE_LIBPCAP - if (list_link_layer_types) { - /* We're supposed to list the link-layer types for an interface; + if (caps_queries) { + /* We're supposed to list the link-layer/timestamp types for an interface; did the user also specify a capture file to be read? */ if (cf_name) { /* Yes - that's bogus. */ - cmdarg_err("You can't specify -L and a capture file to be read."); + cmdarg_err("You can't specify %s and a capture file to be read.", + caps_queries & CAPS_QUERY_LINK_TYPES ? "-L" : "--list-time-stamp-types"); exit_status = INVALID_OPTION; goto clean_exit; } @@ -2079,7 +2092,7 @@ main(int argc, char *argv[]) } /* if requested, list the link layer types and exit */ - if (list_link_layer_types) { + if (caps_queries) { guint i; /* Get the list of link-layer types for the capture devices. */ @@ -2087,6 +2100,7 @@ main(int argc, char *argv[]) interface_options interface_opts; if_capabilities_t *caps; char *auth_str = NULL; + int if_caps_queries = caps_queries; interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i); #ifdef HAVE_PCAP_REMOTE @@ -2102,12 +2116,19 @@ main(int argc, char *argv[]) exit_status = INVALID_CAPABILITY; goto clean_exit; } - if (caps->data_link_types == NULL) { + if ((if_caps_queries & CAPS_QUERY_LINK_TYPES) && caps->data_link_types == NULL) { cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts.name); exit_status = INVALID_DATA_LINK; goto clean_exit; } - capture_opts_print_if_capabilities(caps, interface_opts.name, interface_opts.monitor_mode); + if ((if_caps_queries & CAPS_QUERY_TIMESTAMP_TYPES) && caps->timestamp_types == NULL) { + cmdarg_err("The capture device \"%s\" has no timestamp types.", interface_opts.name); + exit_status = INVALID_TIMESTAMP_TYPE; + goto clean_exit; + } + if (interface_opts.monitor_mode) + if_caps_queries |= CAPS_MONITOR_MODE; + capture_opts_print_if_capabilities(caps, interface_opts.name, if_caps_queries); free_if_capabilities(caps); } exit_status = EXIT_SUCCESS; diff --git a/ui/commandline.c b/ui/commandline.c index dc20e1505b..e692a5e57d 100644 --- a/ui/commandline.c +++ b/ui/commandline.c @@ -109,8 +109,10 @@ commandline_print_usage(gboolean for_help_option) { fprintf(output, " -B size of kernel buffer (def: %dMB)\n", DEFAULT_CAPTURE_BUFFER_SIZE); #endif fprintf(output, " -y link layer type (def: first appropriate)\n"); + fprintf(output, " --time-stamp-type timestamp method for interface\n"); fprintf(output, " -D print list of interfaces and exit\n"); fprintf(output, " -L print list of link-layer types of iface and exit\n"); + fprintf(output, " --list-time-stamp-types print list of timestamp types for iface and exit\n"); fprintf(output, "\n"); fprintf(output, "Capture stop conditions:\n"); fprintf(output, " -c stop after n packets (def: infinite)\n"); @@ -352,6 +354,7 @@ void commandline_other_options(int argc, char *argv[], gboolean opt_reset) { int opt; gboolean arg_error = FALSE; + const char *list_option_supplied = NULL; #ifdef HAVE_LIBPCAP int status; #else @@ -405,6 +408,7 @@ void commandline_other_options(int argc, char *argv[], gboolean opt_reset) #ifdef HAVE_LIBPCAP global_commandline_info.start_capture = FALSE; global_commandline_info.list_link_layer_types = FALSE; + global_commandline_info.list_timestamp_types = FALSE; global_commandline_info.quit_after_cap = getenv("WIRESHARK_QUIT_AFTER_CAPTURE") ? TRUE : FALSE; #endif global_commandline_info.full_screen = FALSE; @@ -420,6 +424,7 @@ void commandline_other_options(int argc, char *argv[], gboolean opt_reset) case 'H': /* Hide capture info dialog box */ case 'p': /* Don't capture in promiscuous mode */ case 'i': /* Use interface x */ + case LONGOPT_SET_TSTAMP_TYPE: /* Set capture timestamp type */ #ifdef HAVE_PCAP_CREATE case 'I': /* Capture in monitor mode, if available */ #endif @@ -469,6 +474,16 @@ void commandline_other_options(int argc, char *argv[], gboolean opt_reset) case 'L': /* Print list of link-layer types and exit */ #ifdef HAVE_LIBPCAP global_commandline_info.list_link_layer_types = TRUE; + list_option_supplied = "-L"; +#else + capture_option_specified = TRUE; + arg_error = TRUE; +#endif + break; + case LONGOPT_LIST_TSTAMP_TYPES: +#ifdef HAVE_LIBPCAP + global_commandline_info.list_timestamp_types = TRUE; + list_option_supplied = "--list-time-stamp-types"; #else capture_option_specified = TRUE; arg_error = TRUE; @@ -631,18 +646,18 @@ void commandline_other_options(int argc, char *argv[], gboolean opt_reset) } #ifdef HAVE_LIBPCAP - if (global_commandline_info.start_capture && global_commandline_info.list_link_layer_types) { + if (global_commandline_info.start_capture && list_option_supplied) { /* Specifying *both* is bogus. */ - cmdarg_err("You can't specify both -L and a live capture."); + cmdarg_err("You can't specify both %s and a live capture.", list_option_supplied); exit(1); } - if (global_commandline_info.list_link_layer_types) { + if (list_option_supplied) { /* We're supposed to list the link-layer types for an interface; did the user also specify a capture file to be read? */ if (global_commandline_info.cf_name) { /* Yes - that's bogus. */ - cmdarg_err("You can't specify -L and a capture file to be read."); + cmdarg_err("You can't specify %s and a capture file to be read.", list_option_supplied); exit(1); } /* No - did they specify a ring buffer option? */ diff --git a/ui/commandline.h b/ui/commandline.h index 85ba97c0c5..344805f1e1 100644 --- a/ui/commandline.h +++ b/ui/commandline.h @@ -37,6 +37,7 @@ typedef struct commandline_param_info { #ifdef HAVE_LIBPCAP gboolean list_link_layer_types; + gboolean list_timestamp_types; gboolean start_capture; gboolean quit_after_cap; #endif diff --git a/ui/gtk/main.c b/ui/gtk/main.c index b9b4292cc4..8214139455 100644 --- a/ui/gtk/main.c +++ b/ui/gtk/main.c @@ -1996,6 +1996,7 @@ main(int argc, char *argv[]) #endif #endif #endif + int caps_queries = 0; gint pl_size = 280, tv_size = 95, bv_size = 75; gchar *rc_file; dfilter_t *rfcode = NULL; @@ -2294,8 +2295,13 @@ main(int argc, char *argv[]) fill_in_local_interfaces(main_window_update); - if (global_commandline_info.start_capture || global_commandline_info.list_link_layer_types) { - /* We're supposed to do a live capture or get a list of link-layer + if (global_commandline_info.list_link_layer_types) + caps_queries |= CAPS_QUERY_LINK_TYPES; + if (global_commandline_info.list_timestamp_types) + caps_queries |= CAPS_QUERY_TIMESTAMP_TYPES; + + if (global_commandline_info.start_capture || caps_queries) { + /* We're supposed to do a live capture or get a list of link-layer/timestamp types for a live capture device; if the user didn't specify an interface to use, pick a default. */ ret = capture_opts_default_iface_if_necessary(&global_capture_opts, @@ -2305,13 +2311,13 @@ main(int argc, char *argv[]) } } - if (global_commandline_info.list_link_layer_types) { + if (caps_queries) { /* Get the list of link-layer types for the capture devices. */ if_capabilities_t *caps; guint i; interface_t device; for (i = 0; i < global_capture_opts.all_ifaces->len; i++) { - + int if_caps_queries = caps_queries; device = g_array_index(global_capture_opts.all_ifaces, interface_t, i); if (device.selected) { gchar* auth_str = NULL; @@ -2342,10 +2348,10 @@ main(int argc, char *argv[]) create_console(); #endif /* _WIN32 */ #if defined(HAVE_PCAP_CREATE) - capture_opts_print_if_capabilities(caps, device.name, device.monitor_mode_supported); -#else - capture_opts_print_if_capabilities(caps, device.name, FALSE); + if (device.monitor_mode_supported) + if_caps_queries |= CAPS_MONITOR_MODE; #endif + capture_opts_print_if_capabilities(caps, device.name, if_caps_queries); #ifdef _WIN32 destroy_console(); #endif /* _WIN32 */ diff --git a/wireshark-qt.cpp b/wireshark-qt.cpp index ab7b99c666..4a704e46cb 100644 --- a/wireshark-qt.cpp +++ b/wireshark-qt.cpp @@ -366,6 +366,7 @@ int main(int argc, char *qt_argv[]) GString *runtime_info_str = NULL; QString dfilter, read_filter; + int caps_queries = 0; /* Start time in microseconds*/ guint64 start_time = g_get_monotonic_time(); #ifdef DEBUG_STARTUP_TIME @@ -714,8 +715,13 @@ int main(int argc, char *qt_argv[]) fill_in_local_interfaces(main_window_update); - if (global_commandline_info.start_capture || global_commandline_info.list_link_layer_types) { - /* We're supposed to do a live capture or get a list of link-layer + if (global_commandline_info.list_link_layer_types) + caps_queries |= CAPS_QUERY_LINK_TYPES; + if (global_commandline_info.list_timestamp_types) + caps_queries |= CAPS_QUERY_TIMESTAMP_TYPES; + + if (global_commandline_info.start_capture || caps_queries) { + /* We're supposed to do a live capture or get a list of link-layer/timestamp types for a live capture device; if the user didn't specify an interface to use, pick a default. */ ret_val = capture_opts_default_iface_if_necessary(&global_capture_opts, @@ -725,13 +731,13 @@ int main(int argc, char *qt_argv[]) } } - if (global_commandline_info.list_link_layer_types) { + if (caps_queries) { /* Get the list of link-layer types for the capture devices. */ if_capabilities_t *caps; guint i; interface_t device; for (i = 0; i < global_capture_opts.all_ifaces->len; i++) { - + int if_caps_queries = caps_queries; device = g_array_index(global_capture_opts.all_ifaces, interface_t, i); if (device.selected) { #if defined(HAVE_PCAP_CREATE) @@ -754,10 +760,10 @@ int main(int argc, char *qt_argv[]) create_console(); #endif /* _WIN32 */ #if defined(HAVE_PCAP_CREATE) - capture_opts_print_if_capabilities(caps, device.name, device.monitor_mode_supported); -#else - capture_opts_print_if_capabilities(caps, device.name, FALSE); + if (device.monitor_mode_supported) + if_caps_queries |= CAPS_MONITOR_MODE; #endif + capture_opts_print_if_capabilities(caps, device.name, if_caps_queries); #ifdef _WIN32 destroy_console(); #endif /* _WIN32 */