From ce38b0cd9bc9f576c3ac4e1da5af3d0a56612754 Mon Sep 17 00:00:00 2001 From: Guy Harris Date: Sun, 22 Aug 2010 19:09:50 -0700 Subject: [PATCH] If the specified time stamp type isn't supported, treat that as a warning. --- pcap-linux.c | 209 ++++++++++++++++++++++++---------- pcap.c | 8 +- pcap/pcap.h | 2 +- pcap_activate.3pcap | 11 +- pcap_set_tstamp_type.3pcap.in | 12 +- 5 files changed, 167 insertions(+), 75 deletions(-) diff --git a/pcap-linux.c b/pcap-linux.c index 024b177..86891f7 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -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 } -static int -activate_mmap(pcap_t *handle) -{ #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, int *status) +{ 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 */ - return 0; -#endif /* HAVE_PACKET_RING */ } +#else /* HAVE_PACKET_RING */ +static int +activate_mmap(pcap_t *handle _U_, int *status _U_) +{ + return 0; +} +#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 *)×ource, 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 *)×ource, 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 9cb481e..143b712 100644 --- 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); diff --git a/pcap/pcap.h b/pcap/pcap.h index 8fcca5a..67d107d 100644 --- a/pcap/pcap.h +++ b/pcap/pcap.h @@ -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 diff --git a/pcap_activate.3pcap b/pcap_activate.3pcap index 219e450..c93df9e 100644 --- a/pcap_activate.3pcap +++ b/pcap_activate.3pcap @@ -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 diff --git a/pcap_set_tstamp_type.3pcap.in b/pcap_set_tstamp_type.3pcap.in index a9b7e48..261c315 100644 --- a/pcap_set_tstamp_type.3pcap.in +++ b/pcap_set_tstamp_type.3pcap.in @@ -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),