]> The Tcpdump Group git mirrors - libpcap/commitdiff
If the specified time stamp type isn't supported, treat that as a warning.
authorGuy Harris <[email protected]>
Mon, 23 Aug 2010 02:09:50 +0000 (19:09 -0700)
committerGuy Harris <[email protected]>
Mon, 23 Aug 2010 02:09:50 +0000 (19:09 -0700)
pcap-linux.c
pcap.c
pcap/pcap.h
pcap_activate.3pcap
pcap_set_tstamp_type.3pcap.in

index 024b1775d444c6e9e5bb41962442c87160d2030b..86891f74bdf47c3e1ab3762c10ae374ed2d68419 100644 (file)
@@ -300,7 +300,7 @@ static short int map_packet_type_to_sll_type(short int);
 static int pcap_activate_linux(pcap_t *);
 static int activate_old(pcap_t *);
 static int activate_new(pcap_t *);
-static int activate_mmap(pcap_t *);
+static int activate_mmap(pcap_t *, int *);
 static int pcap_can_set_rfmon_linux(pcap_t *);
 static int pcap_read_linux(pcap_t *, int, pcap_handler, u_char *);
 static int pcap_read_packet(pcap_t *, pcap_handler, u_char *);
@@ -320,7 +320,7 @@ union thdr {
 #define RING_GET_FRAME(h) (((union thdr **)h->buffer)[h->offset])
 
 static void destroy_ring(pcap_t *handle);
-static int create_ring(pcap_t *handle);
+static int create_ring(pcap_t *handle, int *status);
 static int prepare_tpacket_socket(pcap_t *handle);
 static void pcap_cleanup_linux_mmap(pcap_t *);
 static int pcap_read_linux_mmap(pcap_t *, int, pcap_handler , u_char *);
@@ -1193,18 +1193,30 @@ pcap_activate_linux(pcap_t *handle)
         * to be compatible with older kernels for a while so we are
         * trying both methods with the newer method preferred.
         */
-
-       if ((status = activate_new(handle)) == 1) {
+       status = activate_new(handle);
+       if (status < 0) {
+               /*
+                * Fatal error with the new way; just fail.
+                * status has the error return; if it's PCAP_ERROR,
+                * handle->errbuf has been set appropriately.
+                */
+               goto fail;
+       }
+       if (status == 1) {
                /*
                 * Success.
                 * Try to use memory-mapped access.
                 */
-               status = activate_mmap(handle);
-               switch (status) {
+               switch (activate_mmap(handle, &status)) {
 
                case 1:
-                       /* we succeeded; nothing more to do */
-                       return 0;
+                       /*
+                        * We succeeded.  status has been
+                        * set to the status to return,
+                        * which might be 0, or might be
+                        * a PCAP_WARNING_ value.
+                        */
+                       return status;
 
                case 0:
                        /*
@@ -1213,11 +1225,11 @@ pcap_activate_linux(pcap_t *handle)
                         */
                        break;
 
-               default:
+               case -1:
                        /*
-                        * We failed to set up to use it, or kernel
-                        * supports it, but we failed to enable it;
-                        * the return value is the error status to
+                        * We failed to set up to use it, or the kernel
+                        * supports it, but we failed to enable it.
+                        * status has been set to the error status to
                         * return and, if it's PCAP_ERROR, handle->errbuf
                         * contains the error message.
                         */
@@ -1234,18 +1246,12 @@ pcap_activate_linux(pcap_t *handle)
                         */
                        goto fail;
                }
-       } else {
-               /*
-                * Fatal error with the new way; just fail.
-                * status has the error return; if it's PCAP_ERROR,
-                * handle->errbuf has been set appropriately.
-                */
-               goto fail;
        }
 
        /*
         * We set up the socket, but not with memory-mapped access.
         */
+       status = 0;
        if (handle->opt.buffer_size != 0) {
                /*
                 * Set the socket buffer size to the specified value.
@@ -2982,10 +2988,22 @@ activate_new(pcap_t *handle)
 #endif
 }
 
+#ifdef HAVE_PACKET_RING
+/*
+ * Attempt to activate with memory-mapped access.
+ *
+ * On success, returns 1, and sets *status to 0 if there are no warnings
+ * or to a PCAP_WARNING_ code if there is a warning.
+ *
+ * On failure due to lack of support for memory-mapped capture, returns
+ * 0.
+ *
+ * On error, returns -1, and sets *status to the appropriate error code;
+ * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message.
+ */
 static int 
-activate_mmap(pcap_t *handle)
+activate_mmap(pcap_t *handle, int *status)
 {
-#ifdef HAVE_PACKET_RING
        int ret;
 
        /*
@@ -2997,7 +3015,8 @@ activate_mmap(pcap_t *handle)
                snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                         "can't allocate oneshot buffer: %s",
                         pcap_strerror(errno));
-               return PCAP_ERROR;
+               *status = PCAP_ERROR;
+               return -1;
        }
 
        if (handle->opt.buffer_size == 0) {
@@ -3005,20 +3024,38 @@ activate_mmap(pcap_t *handle)
                handle->opt.buffer_size = 2*1024*1024;
        }
        ret = prepare_tpacket_socket(handle);
-       if (ret != 1) {
+       if (ret == -1) {
                free(handle->md.oneshot_buffer);
+               *status = PCAP_ERROR;
                return ret;
        }
-       ret = create_ring(handle);
-       if (ret != 1) {
+       ret = create_ring(handle, status);
+       if (ret == 0) {
+               /*
+                * We don't support memory-mapped capture; our caller
+                * will fall back on reading from the socket.
+                */
                free(handle->md.oneshot_buffer);
-               return ret;
+               return 0;
+       }
+       if (ret == -1) {
+               /*
+                * Error attempting to enable memory-mapped capture;
+                * fail.  create_ring() has set *status.
+                */
+               free(handle->md.oneshot_buffer);
+               return -1;
        }
 
-       /* override some defaults and inherit the other fields from
-        * activate_new
-        * handle->offset is used to get the current position into the rx ring 
-        * handle->cc is used to store the ring size */
+       /*
+        * Success.  *status has been set either to 0 if there are no
+        * warnings or to a PCAP_WARNING_ value if there is a warning.
+        *
+        * Override some defaults and inherit the other fields from
+        * activate_new.
+        * handle->offset is used to get the current position into the rx ring.
+        * handle->cc is used to store the ring size.
+        */
        handle->read_op = pcap_read_linux_mmap;
        handle->cleanup_op = pcap_cleanup_linux_mmap;
        handle->setfilter_op = pcap_setfilter_linux_mmap;
@@ -3027,12 +3064,21 @@ activate_mmap(pcap_t *handle)
        handle->oneshot_callback = pcap_oneshot_mmap;
        handle->selectable_fd = handle->fd;
        return 1;
+}
 #else /* HAVE_PACKET_RING */
+static int 
+activate_mmap(pcap_t *handle _U_, int *status _U_)
+{
        return 0;
-#endif /* HAVE_PACKET_RING */
 }
+#endif /* HAVE_PACKET_RING */
 
 #ifdef HAVE_PACKET_RING
+/*
+ * Attempt to set the socket to version 2 of the memory-mapped header.
+ * Return 1 if we succeed or if we fail because version 2 isn't
+ * supported; return -1 on any other error, and set handle->errbuf.
+ */
 static int
 prepare_tpacket_socket(pcap_t *handle)
 {
@@ -3084,12 +3130,29 @@ prepare_tpacket_socket(pcap_t *handle)
        return 1;
 }
 
+/*
+ * Attempt to set up memory-mapped access.
+ *
+ * On success, returns 1, and sets *status to 0 if there are no warnings
+ * or to a PCAP_WARNING_ code if there is a warning.
+ *
+ * On failure due to lack of support for memory-mapped capture, returns
+ * 0.
+ *
+ * On error, returns -1, and sets *status to the appropriate error code;
+ * if that is PCAP_ERROR, sets handle->errbuf to the appropriate message.
+ */
 static int
-create_ring(pcap_t *handle)
+create_ring(pcap_t *handle, int *status)
 {
        unsigned i, j, frames_per_block;
        struct tpacket_req req;
 
+       /*
+        * Start out assuming no warnings or errors.
+        */
+       *status = 0;
+
        /* Note that with large snapshot (say 64K) only a few frames 
         * will be available in the ring even with pretty large ring size
         * (and a lot of memory will be unused). 
@@ -3153,39 +3216,62 @@ create_ring(pcap_t *handle)
                        switch (errno) {
 
                        case EPERM:
-                               return PCAP_ERROR_PERM_DENIED;
+                               /*
+                                * Treat this as an error, as the
+                                * user should try to run this
+                                * with the appropriate privileges -
+                                * and, if they can't, shouldn't
+                                * try requesting hardware time stamps.
+                                */
+                               *status = PCAP_ERROR_PERM_DENIED;
+                               return -1;
 
                        case EOPNOTSUPP:
-                               return PCAP_ERROR_TSTAMP_TYPE_NOTSUP:
+                               /*
+                                * Treat this as a warning, as the
+                                * only way to fix the warning is to
+                                * get an adapter that supports hardware
+                                * time stamps.  We'll just fall back
+                                * on the standard host time stamps.
+                                */
+                               *status = PCAP_WARNING_TSTAMP_TYPE_NOTSUP:
+                               break;
 
                        default:
                                snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                                        "SIOCSHWTSTAMP failed: %s",
                                        pcap_strerror(errno));
-                               return PCAP_ERROR;
+                               *status = PCAP_ERROR;
+                               return -1;
                        }
-               }
-
-               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.
+                        * Well, that worked.  Now specify the type of
+                        * hardware time stamp we want for this
+                        * socket.
                         */
-                       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;
+                       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));
+                               *status = PCAP_ERROR;
+                               return -1;
+                       }
                }
        }
 #endif /* HAVE_LINUX_NET_TSTAMP_H && PACKET_TIMESTAMP */
@@ -3224,7 +3310,8 @@ retry:
                snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                    "can't create rx ring on packet socket: %s",
                    pcap_strerror(errno));
-               return PCAP_ERROR;
+               *status = PCAP_ERROR;
+               return -1;
        }
 
        /* memory map the rx ring */
@@ -3237,7 +3324,8 @@ retry:
 
                /* clear the allocated ring on error*/
                destroy_ring(handle);
-               return PCAP_ERROR;
+               *status = PCAP_ERROR;
+               return -1;
        }
 
        /* allocate a ring for each frame header pointer*/
@@ -3249,7 +3337,8 @@ retry:
                    pcap_strerror(errno));
 
                destroy_ring(handle);
-               return PCAP_ERROR;
+               *status = PCAP_ERROR;
+               return -1;
        }
 
        /* fill the header ring with proper frame ptr*/
diff --git a/pcap.c b/pcap.c
index 9cb481ee6e59b23252334db14d5bba00c32fc2a1..143b7128528d3a1397ee163cd9803e9bd395c263 100644 (file)
--- a/pcap.c
+++ b/pcap.c
@@ -391,7 +391,7 @@ pcap_set_tstamp_type(pcap_t *p, int tstamp_type)
         * No.  We support setting the time stamp type, but not to this
         * particular value.
         */
-       return PCAP_ERROR_TSTAMP_TYPE_NOTSUP;
+       return PCAP_WARNING_TSTAMP_TYPE_NOTSUP;
 }
 
 int
@@ -1114,6 +1114,9 @@ pcap_statustostr(int errnum)
        case PCAP_WARNING:
                return("Generic warning");
 
+       case PCAP_WARNING_TSTAMP_TYPE_NOTSUP:
+               return ("That type of time stamp is not supported by that device");
+
        case PCAP_WARNING_PROMISC_NOTSUP:
                return ("That device doesn't support promiscuous mode");
 
@@ -1146,9 +1149,6 @@ pcap_statustostr(int errnum)
 
        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);
index 8fcca5aee3a1d43d61e26e3799f9905c7ba5a5b1..67d107d2ae32e011d60cba6c113da20e599120f8 100644 (file)
@@ -252,7 +252,6 @@ typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
 #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.
@@ -261,6 +260,7 @@ typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
  */
 #define PCAP_WARNING                   1       /* generic warning code */
 #define PCAP_WARNING_PROMISC_NOTSUP    2       /* this device doesn't support promiscuous mode */
+#define PCAP_WARNING_TSTAMP_TYPE_NOTSUP        3       /* the requested time stamp type is not supported */
 
 /*
  * Value to pass to pcap_compile() as the netmask if you don't know what
index 219e4502089907c3a05660cb39ce99b34cac3196..c93df9ea32ab62177475198a4cd4bb3581136ad2 100644 (file)
@@ -43,6 +43,11 @@ returns 0 on success without warnings,
 .B PCAP_WARNING_PROMISC_NOTSUP
 on success on a device that doesn't support promiscuous mode if
 promiscuous mode was requested,
+.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP
+on success if the time stamp type specified in a previous
+.B pcap_set_tstamp_type()
+call isn't supported by the capture source (the time stamp type is
+left as the default),
 .B PCAP_WARNING
 on success with any other warning,
 .B PCAP_ERROR_ACTIVATED
@@ -56,11 +61,7 @@ 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,
-.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
+if the capture source is not up, and
 .B PCAP_ERROR
 if another error occurred.
 If
index a9b7e482c854b5daf55e408d43c84eccf5ecb89f..261c315200c01c2f25feec8a719569e9f565ef02 100644 (file)
@@ -49,13 +49,15 @@ See
 for a list of all the time stamp types.
 .SH RETURN VALUE
 .B pcap_set_tstamp_type()
-returns 0 on success,
+returns 0 on success if the specified time stamp type is expected to be
+supported by the capture device,
+.B PCAP_WARNING_TSTAMP_TYPE_NOTSUP
+on success if the specified time stamp type is not supported by the
+capture device,
 .B PCAP_ERROR_ACTIVATED
-if called on a capture handle that has been activated,
+if called on a capture handle that has been activated, and
 .B PCAP_ERROR_CANTSET_TSTAMP_TYPE
-if the capture device doesn't support setting the time stamp type, and
-.B PCAP_ERROR_TSTAMP_TYPE_NOTSUP
-if the specified time stamp type is not supported by the capture device.
+if the capture device doesn't support setting the time stamp type.
 .SH SEE ALSO
 pcap(3PCAP),
 pcap_list_tstamp_types(3PCAP),