Skip to content

Commit

Permalink
If the specified time stamp type isn't supported, treat that as a war…
Browse files Browse the repository at this point in the history
…ning.
  • Loading branch information
guyharris committed Aug 23, 2010
1 parent fa4435e commit ce38b0c
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 72 deletions.
203 changes: 146 additions & 57 deletions pcap-linux.c
Expand Up @@ -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 *);
Expand All @@ -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 *);
Expand Down Expand Up @@ -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:
/*
Expand All @@ -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.
*/
Expand All @@ -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.
Expand Down Expand Up @@ -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;

/*
Expand All @@ -2997,28 +3015,47 @@ 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) {
/* by default request 2M for the ring buffer */
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;
Expand All @@ -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)
{
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -3224,7 +3310,8 @@ create_ring(pcap_t *handle)
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 */
Expand All @@ -3237,7 +3324,8 @@ create_ring(pcap_t *handle)

/* 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*/
Expand All @@ -3249,7 +3337,8 @@ create_ring(pcap_t *handle)
pcap_strerror(errno));

destroy_ring(handle);
return PCAP_ERROR;
*status = PCAP_ERROR;
return -1;
}

/* fill the header ring with proper frame ptr*/
Expand Down
8 changes: 4 additions & 4 deletions pcap.c
Expand Up @@ -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
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion pcap/pcap.h
Expand Up @@ -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.
Expand All @@ -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
Expand Down

0 comments on commit ce38b0c

Please sign in to comment.