]> The Tcpdump Group git mirrors - libpcap/commitdiff
Add support for setting the time stamp type for a capture.
authorGuy Harris <[email protected]>
Mon, 23 Aug 2010 00:36:27 +0000 (17:36 -0700)
committerGuy Harris <[email protected]>
Mon, 23 Aug 2010 00:36:27 +0000 (17:36 -0700)
Based on a patch from Scott Mcmillan <[email protected]>.

(Second part of the commit.)

.gitignore
Makefile.in
config.h.in
configure
configure.in
pcap-int.h
pcap-linux.c
pcap.c
pcap/pcap.h
pcap_activate.3pcap

index 7d3f3a6b7834377db34c262c4a7e4e3ef92f2262..b8d7f0fb2335a2d10c9ea3abca8785d217da955b 100644 (file)
@@ -19,13 +19,16 @@ pcap-config
 pcap-filter.manmisc
 pcap-linktype.manmisc
 pcap-savefile.manfile
+pcap-tstamp.manmisc
 pcap.3pcap
 pcap_compile.3pcap
 pcap_datalink.3pcap
 pcap_dump_open.3pcap
 pcap_list_datalinks.3pcap
+pcap_list_tstamp_types.3pcap
 pcap_open_dead.3pcap
 pcap_open_offline.3pcap
+pcap_set_tstamp_type.3pcap
 scanner.c
 scanner.h
 selpolltest
index dc51f90d7950445c8f4f76ef5c0fe97679952a4f..129b18edac9e62949451d52e029f0e26f16393f8 100644 (file)
@@ -157,8 +157,10 @@ MAN3PCAP_EXPAND = \
        pcap_datalink.3pcap.in \
        pcap_dump_open.3pcap.in \
        pcap_list_datalinks.3pcap.in \
+       pcap_list_tstamp_types.3pcap.in \
        pcap_open_dead.3pcap.in \
-       pcap_open_offline.3pcap.in
+       pcap_open_offline.3pcap.in \
+       pcap_set_tstamp_type.3pcap.in
 
 MAN3PCAP_NOEXPAND = \
        pcap_activate.3pcap \
@@ -201,7 +203,9 @@ MAN3PCAP_NOEXPAND = \
        pcap_snapshot.3pcap \
        pcap_stats.3pcap \
        pcap_statustostr.3pcap \
-       pcap_strerror.3pcap
+       pcap_strerror.3pcap \
+       pcap_tstamp_type_name_to_val.3pcap \
+       pcap_tstamp_type_val_to_name.3pcap
 
 MAN3PCAP = $(MAN3PCAP_NOEXPAND) $(MAN3PCAP_EXPAND:.in=)
 
@@ -210,7 +214,8 @@ MANFILE = \
 
 MANMISC = \
        pcap-filter.manmisc.in \
-       pcap-linktype.manmisc.in
+       pcap-linktype.manmisc.in \
+       pcap-tstamp.manmisc.in
 
 EXTRA_DIST = \
        $(TESTS_SRC) \
@@ -561,6 +566,9 @@ install: install-shared install-archive pcap-config
        rm -f $(DESTDIR)$(mandir)/man3/pcap_free_datalinks.3pcap
        ln $(DESTDIR)$(mandir)/man3/pcap_list_datalinks.3pcap \
                 $(DESTDIR)$(mandir)/man3/pcap_free_datalinks.3pcap
+       rm -f $(DESTDIR)$(mandir)/man3/pcap_free_tstamp_types.3pcap
+       ln $(DESTDIR)$(mandir)/man3/pcap_list_tstamp_types.3pcap \
+                $(DESTDIR)$(mandir)/man3/pcap_free_tstamp_types.3pcap
        rm -f $(DESTDIR)$(mandir)/man3/pcap_dispatch.3pcap
        ln $(DESTDIR)$(mandir)/man3/pcap_loop.3pcap \
                 $(DESTDIR)$(mandir)/man3/pcap_dispatch.3pcap
@@ -648,6 +656,7 @@ uninstall: uninstall-shared
        rm -f $(DESTDIR)$(mandir)/man3/pcap_perror.3pcap
        rm -f $(DESTDIR)$(mandir)/man3/pcap_sendpacket.3pcap
        rm -f $(DESTDIR)$(mandir)/man3/pcap_free_datalinks.3pcap
+       rm -f $(DESTDIR)$(mandir)/man3/pcap_free_tstamp_types.3pcap
        rm -f $(DESTDIR)$(mandir)/man3/pcap_dispatch.3pcap
        rm -f $(DESTDIR)$(mandir)/man3/pcap_minor_version.3pcap
        rm -f $(DESTDIR)$(mandir)/man3/pcap_next.3pcap
index 55e13dad7af1f42beb4b16d49a03ceed4cc8f006..f988e8f09d90481f26e2a3fb3fd361a5ffc4b908 100644 (file)
@@ -55,6 +55,9 @@
 /* Define to 1 if you have the <limits.h> header file. */
 #undef HAVE_LIMITS_H
 
+/* Define to 1 if you have the <linux/net_tstamp.h> header file. */
+#undef HAVE_LINUX_NET_TSTAMP_H
+
 /* if tp_vlan_tci exists */
 #undef HAVE_LINUX_TPACKET_AUXDATA_TP_VLAN_TCI
 
index ed7fb6d909bba77e223a4d2d022a06f87cb26d10..e85d87e4bc72213b2c187d9cb645b56ce27387eb 100755 (executable)
--- a/configure
+++ b/configure
@@ -10787,6 +10787,155 @@ echo "$as_me: no CAN sniffing support implemented for $host_os" >&6;}
 
 fi
 
+case "$host_os" in
+linux*)
+
+for ac_header in linux/net_tstamp.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+              { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+       ;;
+*)
+       { echo "$as_me:$LINENO: no hardware timestamp support implemented for $host_os" >&5
+echo "$as_me: no hardware timestamp support implemented for $host_os" >&6;}
+       ;;
+esac
+
 # Find a good install program.  We prefer a C program (faster),
 # so one script is as good as another.  But avoid the broken or
 # incompatible versions:
@@ -10871,7 +11020,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 ac_config_headers="$ac_config_headers config.h"
 
 
-ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_list_datalinks.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap"
+ac_config_files="$ac_config_files Makefile pcap-filter.manmisc pcap-linktype.manmisc pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap pcap_open_dead.3pcap pcap_open_offline.3pcap pcap_set_tstamp_type.3pcap"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "pcap-filter.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-filter.manmisc" ;;
     "pcap-linktype.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-linktype.manmisc" ;;
+    "pcap-tstamp.manmisc") CONFIG_FILES="$CONFIG_FILES pcap-tstamp.manmisc" ;;
     "pcap-savefile.manfile") CONFIG_FILES="$CONFIG_FILES pcap-savefile.manfile" ;;
     "pcap.3pcap") CONFIG_FILES="$CONFIG_FILES pcap.3pcap" ;;
     "pcap_compile.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_compile.3pcap" ;;
     "pcap_datalink.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_datalink.3pcap" ;;
     "pcap_dump_open.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_dump_open.3pcap" ;;
     "pcap_list_datalinks.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_datalinks.3pcap" ;;
+    "pcap_list_tstamp_types.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_list_tstamp_types.3pcap" ;;
     "pcap_open_dead.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_dead.3pcap" ;;
     "pcap_open_offline.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_open_offline.3pcap" ;;
+    "pcap_set_tstamp_type.3pcap") CONFIG_FILES="$CONFIG_FILES pcap_set_tstamp_type.3pcap" ;;
 
   *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
 echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
index 43e8f18225f49ac285b43945ae7f9fd52afe12cf..d71d3fd188c8dd9bfd9b63f2e8f459708368ac71 100644 (file)
@@ -1447,15 +1447,26 @@ if test "x$enable_can" != "xno" ; then
        AC_SUBST(CAN_SRC)
 fi
 
+dnl check for hardware timestamp support
+case "$host_os" in
+linux*)
+       AC_CHECK_HEADERS([linux/net_tstamp.h])
+       ;;
+*)
+       AC_MSG_NOTICE(no hardware timestamp support implemented for $host_os)
+       ;;
+esac
+
 AC_PROG_INSTALL
 
 AC_CONFIG_HEADER(config.h)
 
 AC_OUTPUT(Makefile pcap-filter.manmisc pcap-linktype.manmisc
-       pcap-savefile.manfile pcap.3pcap pcap_compile.3pcap
-       pcap_datalink.3pcap pcap_dump_open.3pcap
-       pcap_list_datalinks.3pcap pcap_open_dead.3pcap
-       pcap_open_offline.3pcap)
+       pcap-tstamp.manmisc pcap-savefile.manfile pcap.3pcap
+       pcap_compile.3pcap pcap_datalink.3pcap pcap_dump_open.3pcap
+       pcap_list_datalinks.3pcap pcap_list_tstamp_types.3pcap
+       pcap_open_dead.3pcap pcap_open_offline.3pcap
+       pcap_set_tstamp_type.3pcap)
 
 if test -f .devel ; then
        make depend
index c3afbade52b385fd1a9116faeeda4d431a7b340b..8444e62cee846ea087fd789d7b7e4cf1a95d52eb 100644 (file)
@@ -209,6 +209,7 @@ struct pcap_opt {
        char    *source;
        int     promisc;
        int     rfmon;
+       int     tstamp_type;
 };
 
 /*
@@ -331,6 +332,8 @@ struct pcap {
        char errbuf[PCAP_ERRBUF_SIZE + 1];
        int dlt_count;
        u_int *dlt_list;
+       int tstamp_type_count;
+       u_int *tstamp_type_list;
 
        struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */
 };
index 81bc8d35141ce54ce280a13f74e0a2c29a5c4107..024b1775d444c6e9e5bb41962442c87160d2030b 100644 (file)
@@ -138,6 +138,11 @@ static const char rcsid[] _U_ =
 #include <poll.h>
 #include <dirent.h>
 
+#ifdef HAVE_LINUX_NET_TSTAMP_H
+#include <linux/net_tstamp.h>
+#include <linux/sockios.h>
+#endif
+
 /*
  * Got Wireless Extensions?
  */
@@ -411,6 +416,28 @@ pcap_create(const char *device, char *ebuf)
 
        handle->activate_op = pcap_activate_linux;
        handle->can_set_rfmon_op = pcap_can_set_rfmon_linux;
+#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
+       /*
+        * We claim that we support:
+        *
+        *      software time stamps, with no details about their precision;
+        *      hardware time stamps, synced to the host time;
+        *      hardware time stamps, not synced to the host time.
+        *
+        * XXX - we can't ask a device whether it supports
+        * hardware time stamps, so we just claim all devices do.
+        */
+       handle->tstamp_type_count = 3;
+       handle->tstamp_type_list = malloc(3 * sizeof(u_int));
+       if (handle->tstamp_type_list == NULL) {
+               free(handle);
+               return NULL;
+       }
+       handle->tstamp_type_list[0] = PCAP_TSTAMP_HOST;
+       handle->tstamp_type_list[1] = PCAP_TSTAMP_ADAPTER;
+       handle->tstamp_type_list[2] = PCAP_TSTAMP_ADAPTER_UNSYNC;
+#endif
+
        return handle;
 }
 
@@ -1172,7 +1199,8 @@ pcap_activate_linux(pcap_t *handle)
                 * Success.
                 * Try to use memory-mapped access.
                 */
-               switch (activate_mmap(handle)) {
+               status = activate_mmap(handle);
+               switch (status) {
 
                case 1:
                        /* we succeeded; nothing more to do */
@@ -1183,17 +1211,16 @@ pcap_activate_linux(pcap_t *handle)
                         * Kernel doesn't support it - just continue
                         * with non-memory-mapped access.
                         */
-                       status = 0;
                        break;
 
-               case -1:
+               default:
                        /*
                         * We failed to set up to use it, or kernel
                         * supports it, but we failed to enable it;
-                        * return an error.  handle->errbuf contains
-                        * an error message.
+                        * the return value is the error status to
+                        * return and, if it's PCAP_ERROR, handle->errbuf
+                        * contains the error message.
                         */
-                       status = PCAP_ERROR;
                        goto fail;
                }
        }
@@ -3083,6 +3110,86 @@ create_ring(pcap_t *handle)
 
        frames_per_block = req.tp_block_size/req.tp_frame_size;
 
+       /*
+        * PACKET_TIMESTAMP was added after linux/net_tstamp.h was,
+        * so we check for PACKET_TIMESTAMP.  We check for
+        * linux/net_tstamp.h just in case a system somehow has
+        * PACKET_TIMESTAMP but not linux/net_tstamp.h; that might
+        * be unnecessary.
+        *
+        * SIOCSHWTSTAMP was introduced in the patch that introduced
+        * linux/net_tstamp.h, so we don't bother checking whether
+        * SIOCSHWTSTAMP is defined (if your Linux system has
+        * linux/net_tstamp.h but doesn't define SIOCSHWTSTAMP, your
+        * Linux system is badly broken).
+        */
+#if defined(HAVE_LINUX_NET_TSTAMP_H) && defined(PACKET_TIMESTAMP)
+       /*
+        * If we were told to do so, ask the kernel and the driver
+        * to use hardware timestamps.
+        *
+        * Hardware timestamps are only supported with mmapped
+        * captures.
+        */
+       if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER ||
+           handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER_UNSYNCED) {
+               struct hwtstamp_config hwconfig;
+               struct ifreq ifr;
+               int timesource;
+
+               /*
+                * Ask for hardware time stamps on all packets,
+                * including transmitted packets.
+                */
+               memset(&hwconfig, 0, sizeof(hwconfig));
+               hwconfig.tx_type = HWTSTAMP_TX_ON;
+               hwconfig.rx_filter = HWTSTAMP_FILTER_ALL;
+
+               memset(&ifr, 0, sizeof(ifr));
+               strcpy(ifr.ifr_name, handle->opt.source);
+               ifr.ifr_data = (void *)&hwconfig;
+
+               if (ioctl(handle->fd, SIOCSHWTSTAMP, &ifr) < 0) {
+                       switch (errno) {
+
+                       case EPERM:
+                               return PCAP_ERROR_PERM_DENIED;
+
+                       case EOPNOTSUPP:
+                               return PCAP_ERROR_TSTAMP_TYPE_NOTSUP:
+
+                       default:
+                               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+                                       "SIOCSHWTSTAMP failed: %s",
+                                       pcap_strerror(errno));
+                               return PCAP_ERROR;
+                       }
+               }
+
+               if (handle->opt.tstamp_type == PCAP_TSTAMP_ADAPTER) {
+                       /*
+                        * Hardware timestamp, synchronized
+                        * with the system clock.
+                        */
+                       timesource = SOF_TIMESTAMPING_SYS_HARDWARE;
+               } else {
+                       /*
+                        * PCAP_TSTAMP_ADAPTER_UNSYNCED - hardware
+                        * timestamp, not synchronized with the
+                        * system clock.
+                        */
+                       timesource = SOF_TIMESTAMPING_RAW_HARDWARE;
+               }
+               if (setsockopt(handle->fd, SOL_PACKET, PACKET_TIMESTAMP,
+                       (void *)&timesource, sizeof(timesource))) {
+                       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 
+                               "can't set PACKET_TIMESTAMP: %s", 
+                               pcap_strerror(errno));
+                       return PCAP_ERROR;
+               }
+       }
+#endif /* HAVE_LINUX_NET_TSTAMP_H && PACKET_TIMESTAMP */
+
        /* ask the kernel to create the ring */
 retry:
        req.tp_block_nr = req.tp_frame_nr / frames_per_block;
@@ -3117,7 +3224,7 @@ retry:
                snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                    "can't create rx ring on packet socket: %s",
                    pcap_strerror(errno));
-               return -1;
+               return PCAP_ERROR;
        }
 
        /* memory map the rx ring */
@@ -3130,7 +3237,7 @@ retry:
 
                /* clear the allocated ring on error*/
                destroy_ring(handle);
-               return -1;
+               return PCAP_ERROR;
        }
 
        /* allocate a ring for each frame header pointer*/
@@ -3142,7 +3249,7 @@ retry:
                    pcap_strerror(errno));
 
                destroy_ring(handle);
-               return -1;
+               return PCAP_ERROR;
        }
 
        /* fill the header ring with proper frame ptr*/
diff --git a/pcap.c b/pcap.c
index 7c94f8bb321faf8454c13dcbf4174b1438df6527..9cb481ee6e59b23252334db14d5bba00c32fc2a1 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -104,6 +104,56 @@ pcap_cant_set_rfmon(pcap_t *p _U_)
        return (0);
 }
 
+/*
+ * Sets *tstamp_typesp to point to an array 1 or more supported time stamp
+ * types; the return value is the number of supported time stamp types.
+ * The list should be freed by a call to pcap_free_tstamp_types() when
+ * you're done with it.
+ *
+ * A return value of 0 means "you don't get a choice of time stamp type",
+ * in which case *tstamp_typesp is set to null.
+ *
+ * PCAP_ERROR is returned on error.
+ */
+int
+pcap_list_tstamp_types(pcap_t *p, int **tstamp_typesp)
+{
+       if (p->tstamp_type_count == 0) {
+               /*
+                * We don't support multiple time stamp types.
+                */
+               *tstamp_typesp = NULL;
+       } else {
+               *tstamp_typesp = (int*)calloc(sizeof(**tstamp_typesp),
+                   p->tstamp_type_count);
+               if (*tstamp_typesp == NULL) {
+                       (void)snprintf(p->errbuf, sizeof(p->errbuf),
+                           "malloc: %s", pcap_strerror(errno));
+                       return (PCAP_ERROR);
+               }
+               (void)memcpy(*tstamp_typesp, p->tstamp_type_list,
+                   sizeof(**tstamp_typesp) * p->tstamp_type_count);
+       }
+       return (p->tstamp_type_count);
+}
+
+/*
+ * In Windows, you might have a library built with one version of the
+ * C runtime library and an application built with another version of
+ * the C runtime library, which means that the library might use one
+ * version of malloc() and free() and the application might use another
+ * version of malloc() and free().  If so, that means something
+ * allocated by the library cannot be freed by the application, so we
+ * need to have a pcap_free_tstamp_types() routine to free up the list
+ * allocated by pcap_list_tstamp_types(), even though it's just a wrapper
+ * around free().
+ */
+void
+pcap_free_tstamp_types(int *tstamp_type_list)
+{
+       free(tstamp_type_list);
+}
+
 /*
  * Default one-shot callback; overridden for capture types where the
  * packet data cannot be guaranteed to be available after the callback
@@ -258,6 +308,7 @@ pcap_create_common(const char *source, char *ebuf)
        pcap_set_snaplen(p, 65535);     /* max packet size */
        p->opt.promisc = 0;
        p->opt.buffer_size = 0;
+       p->opt.tstamp_type = -1;        /* default to not setting time stamp type */
        return (p);
 }
 
@@ -308,6 +359,41 @@ pcap_set_timeout(pcap_t *p, int timeout_ms)
        return 0;
 }
 
+int
+pcap_set_tstamp_type(pcap_t *p, int tstamp_type)
+{
+       int i;
+
+       if (pcap_check_activated(p))
+               return PCAP_ERROR_ACTIVATED;
+
+       /*
+        * If p->tstamp_type_count is 0, we don't support setting
+        * the time stamp type at all.
+        */
+       if (p->tstamp_type_count == 0)
+               return PCAP_ERROR_CANTSET_TSTAMP_TYPE;
+
+       /*
+        * Check whether we claim to support this type of time stamp.
+        */
+       for (i = 0; i < p->tstamp_type_count; i++) {
+               if (p->tstamp_type_list[i] == tstamp_type) {
+                       /*
+                        * Yes.
+                        */
+                       p->opt.tstamp_type = tstamp_type;
+                       return 0;
+               }
+       }
+
+       /*
+        * No.  We support setting the time stamp type, but not to this
+        * particular value.
+        */
+       return PCAP_ERROR_TSTAMP_TYPE_NOTSUP;
+}
+
 int
 pcap_set_buffer_size(pcap_t *p, int buffer_size)
 {
@@ -571,6 +657,91 @@ unsupported:
        return (-1);
 }
 
+/*
+ * This array is designed for mapping upper and lower case letter
+ * together for a case independent comparison.  The mappings are
+ * based upon ascii character sequences.
+ */
+static const u_char charmap[] = {
+       (u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003',
+       (u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007',
+       (u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013',
+       (u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017',
+       (u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023',
+       (u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027',
+       (u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033',
+       (u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037',
+       (u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043',
+       (u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047',
+       (u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053',
+       (u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057',
+       (u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063',
+       (u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067',
+       (u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073',
+       (u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077',
+       (u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143',
+       (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
+       (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
+       (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
+       (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
+       (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
+       (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133',
+       (u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137',
+       (u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143',
+       (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
+       (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
+       (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
+       (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
+       (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
+       (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173',
+       (u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177',
+       (u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203',
+       (u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207',
+       (u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213',
+       (u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217',
+       (u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223',
+       (u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227',
+       (u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233',
+       (u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237',
+       (u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243',
+       (u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247',
+       (u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253',
+       (u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257',
+       (u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263',
+       (u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267',
+       (u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273',
+       (u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277',
+       (u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343',
+       (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
+       (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
+       (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
+       (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
+       (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
+       (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333',
+       (u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337',
+       (u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343',
+       (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
+       (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
+       (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
+       (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
+       (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
+       (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373',
+       (u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377',
+};
+
+int
+pcap_strcasecmp(const char *s1, const char *s2)
+{
+       register const u_char   *cm = charmap,
+                               *us1 = (const u_char *)s1,
+                               *us2 = (const u_char *)s2;
+
+       while (cm[*us1] == cm[*us2++])
+               if (*us1++ == '\0')
+                       return(0);
+       return (cm[*us1] - cm[*--us2]);
+}
+
 struct dlt_choice {
        const char *name;
        const char *description;
@@ -677,91 +848,6 @@ static struct dlt_choice dlt_choices[] = {
        DLT_CHOICE_SENTINEL
 };
 
-/*
- * This array is designed for mapping upper and lower case letter
- * together for a case independent comparison.  The mappings are
- * based upon ascii character sequences.
- */
-static const u_char charmap[] = {
-       (u_char)'\000', (u_char)'\001', (u_char)'\002', (u_char)'\003',
-       (u_char)'\004', (u_char)'\005', (u_char)'\006', (u_char)'\007',
-       (u_char)'\010', (u_char)'\011', (u_char)'\012', (u_char)'\013',
-       (u_char)'\014', (u_char)'\015', (u_char)'\016', (u_char)'\017',
-       (u_char)'\020', (u_char)'\021', (u_char)'\022', (u_char)'\023',
-       (u_char)'\024', (u_char)'\025', (u_char)'\026', (u_char)'\027',
-       (u_char)'\030', (u_char)'\031', (u_char)'\032', (u_char)'\033',
-       (u_char)'\034', (u_char)'\035', (u_char)'\036', (u_char)'\037',
-       (u_char)'\040', (u_char)'\041', (u_char)'\042', (u_char)'\043',
-       (u_char)'\044', (u_char)'\045', (u_char)'\046', (u_char)'\047',
-       (u_char)'\050', (u_char)'\051', (u_char)'\052', (u_char)'\053',
-       (u_char)'\054', (u_char)'\055', (u_char)'\056', (u_char)'\057',
-       (u_char)'\060', (u_char)'\061', (u_char)'\062', (u_char)'\063',
-       (u_char)'\064', (u_char)'\065', (u_char)'\066', (u_char)'\067',
-       (u_char)'\070', (u_char)'\071', (u_char)'\072', (u_char)'\073',
-       (u_char)'\074', (u_char)'\075', (u_char)'\076', (u_char)'\077',
-       (u_char)'\100', (u_char)'\141', (u_char)'\142', (u_char)'\143',
-       (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
-       (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
-       (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
-       (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
-       (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
-       (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\133',
-       (u_char)'\134', (u_char)'\135', (u_char)'\136', (u_char)'\137',
-       (u_char)'\140', (u_char)'\141', (u_char)'\142', (u_char)'\143',
-       (u_char)'\144', (u_char)'\145', (u_char)'\146', (u_char)'\147',
-       (u_char)'\150', (u_char)'\151', (u_char)'\152', (u_char)'\153',
-       (u_char)'\154', (u_char)'\155', (u_char)'\156', (u_char)'\157',
-       (u_char)'\160', (u_char)'\161', (u_char)'\162', (u_char)'\163',
-       (u_char)'\164', (u_char)'\165', (u_char)'\166', (u_char)'\167',
-       (u_char)'\170', (u_char)'\171', (u_char)'\172', (u_char)'\173',
-       (u_char)'\174', (u_char)'\175', (u_char)'\176', (u_char)'\177',
-       (u_char)'\200', (u_char)'\201', (u_char)'\202', (u_char)'\203',
-       (u_char)'\204', (u_char)'\205', (u_char)'\206', (u_char)'\207',
-       (u_char)'\210', (u_char)'\211', (u_char)'\212', (u_char)'\213',
-       (u_char)'\214', (u_char)'\215', (u_char)'\216', (u_char)'\217',
-       (u_char)'\220', (u_char)'\221', (u_char)'\222', (u_char)'\223',
-       (u_char)'\224', (u_char)'\225', (u_char)'\226', (u_char)'\227',
-       (u_char)'\230', (u_char)'\231', (u_char)'\232', (u_char)'\233',
-       (u_char)'\234', (u_char)'\235', (u_char)'\236', (u_char)'\237',
-       (u_char)'\240', (u_char)'\241', (u_char)'\242', (u_char)'\243',
-       (u_char)'\244', (u_char)'\245', (u_char)'\246', (u_char)'\247',
-       (u_char)'\250', (u_char)'\251', (u_char)'\252', (u_char)'\253',
-       (u_char)'\254', (u_char)'\255', (u_char)'\256', (u_char)'\257',
-       (u_char)'\260', (u_char)'\261', (u_char)'\262', (u_char)'\263',
-       (u_char)'\264', (u_char)'\265', (u_char)'\266', (u_char)'\267',
-       (u_char)'\270', (u_char)'\271', (u_char)'\272', (u_char)'\273',
-       (u_char)'\274', (u_char)'\275', (u_char)'\276', (u_char)'\277',
-       (u_char)'\300', (u_char)'\341', (u_char)'\342', (u_char)'\343',
-       (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
-       (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
-       (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
-       (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
-       (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
-       (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\333',
-       (u_char)'\334', (u_char)'\335', (u_char)'\336', (u_char)'\337',
-       (u_char)'\340', (u_char)'\341', (u_char)'\342', (u_char)'\343',
-       (u_char)'\344', (u_char)'\345', (u_char)'\346', (u_char)'\347',
-       (u_char)'\350', (u_char)'\351', (u_char)'\352', (u_char)'\353',
-       (u_char)'\354', (u_char)'\355', (u_char)'\356', (u_char)'\357',
-       (u_char)'\360', (u_char)'\361', (u_char)'\362', (u_char)'\363',
-       (u_char)'\364', (u_char)'\365', (u_char)'\366', (u_char)'\367',
-       (u_char)'\370', (u_char)'\371', (u_char)'\372', (u_char)'\373',
-       (u_char)'\374', (u_char)'\375', (u_char)'\376', (u_char)'\377',
-};
-
-int
-pcap_strcasecmp(const char *s1, const char *s2)
-{
-       register const u_char   *cm = charmap,
-                               *us1 = (const u_char *)s1,
-                               *us2 = (const u_char *)s2;
-
-       while (cm[*us1] == cm[*us2++])
-               if (*us1++ == '\0')
-                       return(0);
-       return (cm[*us1] - cm[*--us2]);
-}
-
 int
 pcap_datalink_name_to_val(const char *name)
 {
@@ -799,6 +885,57 @@ pcap_datalink_val_to_description(int dlt)
        return (NULL);
 }
 
+struct tstamp_type_choice {
+       const char *name;
+       const char *description;
+       int     type;
+};
+
+static struct tstamp_type_choice tstamp_type_choices[] = {
+       { "host", "Host", PCAP_TSTAMP_HOST },
+       { "host_lowprec", "Host, low precision", PCAP_TSTAMP_HOST_LOWPREC },
+       { "host_hiprec", "Host, high precision", PCAP_TSTAMP_HOST_HIPREC },
+       { "adapter", "Adapter", PCAP_TSTAMP_ADAPTER },
+       { "adapter_unsynced", "Adapter, not synced with system time", PCAP_TSTAMP_ADAPTER_UNSYNCED },
+       { NULL, NULL, 0 }
+};
+
+int
+pcap_tstamp_type_name_to_val(const char *name)
+{
+       int i;
+
+       for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+               if (pcap_strcasecmp(tstamp_type_choices[i].name, name) == 0)
+                       return (tstamp_type_choices[i].type);
+       }
+       return (PCAP_ERROR);
+}
+
+const char *
+pcap_tstamp_type_val_to_name(int tstamp_type)
+{
+       int i;
+
+       for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+               if (tstamp_type_choices[i].type == tstamp_type)
+                       return (tstamp_type_choices[i].name);
+       }
+       return (NULL);
+}
+
+const char *
+pcap_tstamp_type_val_to_description(int tstamp_type)
+{
+       int i;
+
+       for (i = 0; tstamp_type_choices[i].name != NULL; i++) {
+               if (tstamp_type_choices[i].type == tstamp_type)
+                       return (tstamp_type_choices[i].description);
+       }
+       return (NULL);
+}
+
 int
 pcap_snapshot(pcap_t *p)
 {
@@ -1006,6 +1143,12 @@ pcap_statustostr(int errnum)
 
        case PCAP_ERROR_IFACE_NOT_UP:
                return ("That device is not up");
+
+       case PCAP_ERROR_CANTSET_TSTAMP_TYPE:
+               return ("That device doesn't support setting the time stamp type");
+
+       case PCAP_ERROR_TSTAMP_TYPE_NOTSUP:
+               return ("That type of time stamp is not supported by that device");
        }
        (void)snprintf(ebuf, sizeof ebuf, "Unknown error: %d", errnum);
        return(ebuf);
@@ -1213,6 +1356,11 @@ pcap_cleanup_live_common(pcap_t *p)
                p->dlt_list = NULL;
                p->dlt_count = 0;
        }
+       if (p->tstamp_type_list != NULL) {
+               free(p->tstamp_type_list);
+               p->tstamp_type_list = NULL;
+               p->tstamp_type_count = 0;
+       }
        pcap_freecode(&p->fcode);
 #if !defined(WIN32) && !defined(MSDOS)
        if (p->fd >= 0) {
index 05ba31f35be91d1d9af8c664c4c1b085b123364c..8fcca5aee3a1d43d61e26e3799f9905c7ba5a5b1 100644 (file)
@@ -251,6 +251,8 @@ typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
 #define PCAP_ERROR_NOT_RFMON           -7      /* operation supported only in monitor mode */
 #define PCAP_ERROR_PERM_DENIED         -8      /* no permission to open the device */
 #define PCAP_ERROR_IFACE_NOT_UP                -9      /* interface isn't up */
+#define PCAP_ERROR_CANTSET_TSTAMP_TYPE -10     /* this device doesn't support setting the time stamp type */
+#define PCAP_ERROR_TSTAMP_TYPE_NOTSUP  -11     /* the requested time stamp type is not supported */
 
 /*
  * Warning codes for the pcap API.
@@ -275,9 +277,60 @@ int        pcap_set_promisc(pcap_t *, int);
 int    pcap_can_set_rfmon(pcap_t *);
 int    pcap_set_rfmon(pcap_t *, int);
 int    pcap_set_timeout(pcap_t *, int);
+int    pcap_set_tstamp_type(pcap_t *, int);
 int    pcap_set_buffer_size(pcap_t *, int);
 int    pcap_activate(pcap_t *);
 
+int    pcap_list_tstamp_types(pcap_t *, int **);
+void   pcap_free_tstamp_types(int *);
+int    pcap_tstamp_type_name_to_val(const char *);
+const char *pcap_tstamp_type_val_to_name(int);
+const char *pcap_tstamp_type_val_to_description(int);
+
+/*
+ * Time stamp types.
+ * Not all systems and interfaces will necessarily support all of these.
+ *
+ * A system that supports PCAP_TSTAMP_HOST is offering time stamps
+ * provided by the host machine, rather than by the capture device,
+ * but not committing to any characteristics of the time stamp;
+ * it will not offer any of the PCAP_TSTAMP_HOST_ subtypes.
+ *
+ * PCAP_TSTAMP_HOST_LOWPREC is a time stamp, provided by the host machine,
+ * that's low-precision but relatively cheap to fetch; it's normally done
+ * using the system clock, so it's normally synchronized with times you'd
+ * fetch from system calls.
+ *
+ * PCAP_TSTAMP_HOST_HIPREC is a time stamp, provided by the host machine,
+ * that's high-precision; it might be more expensive to fetch.  It might
+ * or might not be synchronized with the system clock, and might have
+ * problems with time stamps for packets received on different CPUs,
+ * depending on the platform.
+ *
+ * PCAP_TSTAMP_ADAPTER is a high-precision time stamp supplied by the
+ * capture device; it's synchronized with the system clock.
+ *
+ * PCAP_TSTAMP_ADAPTER_UNSYNC is a high-precision time stamp supplied by
+ * the capture device; it's not synchronized with the system clock.
+ *
+ * Note that time stamps synchronized with the system clock can go
+ * backwards, as the system clock can go backwards.  If a clock is
+ * not in sync with the system clock, that could be because the
+ * system clock isn't keeping accurate time, because the other
+ * clock isn't keeping accurate time, or both.
+ *
+ * Note that host-provided time stamps generally correspond to the
+ * time when the time-stamping code sees the packet; this could
+ * be some unknown amount of time after the first or last bit of
+ * the packet is received by the network adapter, due to batching
+ * of interrupts for packet arrival, queueing delays, etc..
+ */
+#define PCAP_TSTAMP_HOST               0       /* host-provided, unknown characteristics */
+#define PCAP_TSTAMP_HOST_LOWPREC       1       /* host-provided, low precision */
+#define PCAP_TSTAMP_HOST_HIPREC                2       /* host-provided, high precision */
+#define PCAP_TSTAMP_ADAPTER            3       /* device-provided, synced with the system clock */
+#define PCAP_TSTAMP_ADAPTER_UNSYNCED   4       /* device-provided, not synced with the system clock */
+
 pcap_t *pcap_open_live(const char *, int, int, int, char *);
 pcap_t *pcap_open_dead(int, int);
 pcap_t *pcap_open_offline(const char *, char *);
index b33fa530fd28942ec773cae6498051806543296a..219e4502089907c3a05660cb39ce99b34cac3196 100644 (file)
@@ -56,7 +56,11 @@ if the process doesn't have permission to open the capture source,
 if monitor mode was specified but the capture source doesn't support
 monitor mode,
 .B PCAP_ERROR_IFACE_NOT_UP
-if the capture source is not up, and
+if the capture source is not up,
+.B PCAP_ERROR_TSTAMP_TYPE_NOTSUP
+if the time stamp specified in a previous
+.B pcap_set_tstamp_type()
+call isn't supported by the capture source, and
 .B PCAP_ERROR
 if another error occurred.
 If