X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/5cadf6324e304be8ce9aead55c60922b40d2283f..09b51d326c38ea8e10ce4da09c09d50e08c5aeb8:/pcap-dag.c diff --git a/pcap-dag.c b/pcap-dag.c index 1e6b3da6..f261ead0 100644 --- a/pcap-dag.c +++ b/pcap-dag.c @@ -1,18 +1,10 @@ /* - * pcap-dag.c: Packet capture interface for Emulex EndaceDAG cards. - * - * The functionality of this code attempts to mimic that of pcap-linux as much - * as possible. This code is compiled in several different ways depending on - * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not - * defined it should not get compiled in, otherwise if DAG_ONLY is defined then - * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY - * is not defined then nothing is altered - the dag_ functions will be - * called as required from their pcap-linux/bpf equivalents. + * pcap-dag.c: Packet capture interface for Endace DAG cards. * * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) * Modifications: Jesper Peterson * Koryn Grant - * Stephen Donnelly + * Stephen Donnelly */ #ifdef HAVE_CONFIG_H @@ -27,7 +19,6 @@ #include "pcap-int.h" -#include #include #include #include @@ -187,6 +178,8 @@ struct pcap_dag { * Same as in linux above, introduce * generally? */ dag_card_ref_t dag_ref; /* DAG Configuration/Status API card reference */ + dag_component_t dag_root; /* DAG CSAPI Root component */ + attr_uuid_t drop_attr; /* DAG Stream Drop Attribute handle, if available */ struct timeval required_select_timeout; /* Timeout caller must use in event loops */ }; @@ -214,14 +207,13 @@ static unsigned char TempPkt[MAX_DAG_PACKET]; #define dag_size_t uint32_t #endif -static int dag_setfilter(pcap_t *p, struct bpf_program *fp); static int dag_stats(pcap_t *p, struct pcap_stat *ps); static int dag_set_datalink(pcap_t *p, int dlt); static int dag_get_datalink(pcap_t *p); static int dag_setnonblock(pcap_t *p, int nonblock); static void -delete_pcap_dag(pcap_t *p) +delete_pcap_dag(const pcap_t *p) { pcap_dag_node_t *curr = NULL, *prev = NULL; @@ -256,12 +248,18 @@ dag_platform_cleanup(pcap_t *p) if(pd->dag_ref != NULL) { dag_config_dispose(pd->dag_ref); + /* + * Note: we don't need to call close(p->fd) or + * dag_close(p->fd), as dag_config_dispose(pd->dag_ref) + * does this. + * + * Set p->fd to -1 to make sure that's not done. + */ p->fd = -1; pd->dag_ref = NULL; } delete_pcap_dag(p); pcap_cleanup_live_common(p); - /* Note: don't need to call close(p->fd) or dag_close(p->fd) as dag_config_dispose(pd->dag_ref) does this. */ } static void @@ -301,7 +299,7 @@ new_pcap_dag(pcap_t *p) } static unsigned int -dag_erf_ext_header_count(uint8_t * erf, size_t len) +dag_erf_ext_header_count(const uint8_t *erf, size_t len) { uint32_t hdr_num = 0; uint8_t hdr_type; @@ -335,7 +333,7 @@ dag_erf_ext_header_count(uint8_t * erf, size_t len) /* * Read at most max_packets from the capture stream and call the callback * for each of them. Returns the number of packets handled, -1 if an - * error occured, or -2 if we were told to break out of the loop. + * error occurred, or -2 if we were told to break out of the loop. */ static int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) @@ -393,7 +391,12 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } - /* Process the packets. */ + /* + * Process the packets. + * + * This assumes that a single buffer of packets will have + * <= INT_MAX packets, so the packet count doesn't overflow. + */ while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) { unsigned short packet_len = 0; @@ -421,7 +424,8 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) rlen = ntohs(header->rlen); if (rlen < dag_record_size) { - strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); + pcap_strlcpy(p->errbuf, "dag_read: record too small", + PCAP_ERRBUF_SIZE); return -1; } pd->dag_mem_bottom += rlen; @@ -439,12 +443,8 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) break; default: - if (header->lctr) { - if (pd->stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { - pd->stat.ps_drop = UINT_MAX; - } else { - pd->stat.ps_drop += ntohs(header->lctr); - } + if ( (pd->drop_attr == kNullAttributeUuid) && (header->lctr) ) { + pd->stat.ps_drop += ntohs(header->lctr); } } @@ -668,7 +668,7 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) caplen = p->snapshot; /* Run the packet filter if there is one. */ - if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { + if ((p->fcode.bf_insns == NULL) || pcap_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { /* convert between timestamp formats */ register unsigned long long ts; @@ -722,9 +722,9 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } static int -dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) +dag_inject(pcap_t *p, const void *buf _U_, int size _U_) { - strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", + pcap_strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", PCAP_ERRBUF_SIZE); return (-1); } @@ -736,7 +736,7 @@ dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) * API polling parameters. * * snaplen is now also ignored, until we get per-stream slen support. Set - * slen with approprite DAG tool BEFORE pcap_activate(). + * slen with appropriate DAG tool BEFORE pcap_activate(). * * See also pcap(3). */ @@ -748,18 +748,20 @@ static int dag_activate(pcap_t* p) daginf_t* daginf; char * newDev = NULL; char * device = p->opt.device; + int ret; dag_size_t mindata; struct timeval maxwait; struct timeval poll; if (device == NULL) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); - return -1; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); + return PCAP_ERROR; } /* Initialize some components of the pcap structure. */ newDev = (char *)malloc(strlen(device) + 16); if (newDev == NULL) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "Can't allocate string for device name"); goto fail; @@ -767,6 +769,13 @@ static int dag_activate(pcap_t* p) /* Parse input name to get dag device and stream number if provided */ if (dag_parse_name(device, newDev, strlen(device) + 16, &pd->dag_stream) < 0) { + /* + * XXX - it'd be nice if this indicated what was wrong + * with the name. Does this reliably set errno? + * Should this return PCAP_ERROR_NO_SUCH_DEVICE in some + * cases? + */ + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_parse_name"); goto fail; @@ -774,35 +783,68 @@ static int dag_activate(pcap_t* p) device = newDev; if (pd->dag_stream%2) { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture"); + ret = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture"); goto fail; } /* setup device parameters */ if((pd->dag_ref = dag_config_init((char *)device)) == NULL) { - pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, - errno, "dag_config_init %s", device); + /* + * XXX - does this reliably set errno? + */ + if (errno == ENOENT) { + /* + * There's nothing more to say, so clear + * the error message. + */ + ret = PCAP_ERROR_NO_SUCH_DEVICE; + p->errbuf[0] = '\0'; + } else if (errno == EPERM || errno == EACCES) { + ret = PCAP_ERROR_PERM_DENIED; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "Attempt to open %s failed with %s - additional privileges may be required", + device, (errno == EPERM) ? "EPERM" : "EACCES"); + } else { + ret = PCAP_ERROR; + pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "dag_config_init %s", device); + } goto fail; } if((p->fd = dag_config_get_card_fd(pd->dag_ref)) < 0) { + /* + * XXX - does this reliably set errno? + */ + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_config_get_card_fd %s", device); - goto fail; + goto failclose; } /* Open requested stream. Can fail if already locked or on error */ if (dag_attach_stream64(p->fd, pd->dag_stream, 0, 0) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_attach_stream"); goto failclose; } + /* Try to find Stream Drop attribute */ + pd->drop_attr = kNullAttributeUuid; + pd->dag_root = dag_config_get_root_component(pd->dag_ref); + if ( dag_component_get_subcomponent(pd->dag_root, kComponentStreamFeatures, 0) ) + { + pd->drop_attr = dag_config_get_indexed_attribute_uuid(pd->dag_ref, kUint32AttributeStreamDropCount, pd->dag_stream/2); + } + /* Set up default poll parameters for stream * Can be overridden by pcap_set_nonblock() */ if (dag_get_stream_poll64(p->fd, pd->dag_stream, &mindata, &maxwait, &poll) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_get_stream_poll"); goto faildetach; @@ -847,6 +889,7 @@ static int dag_activate(pcap_t* p) if (dag_set_stream_poll64(p->fd, pd->dag_stream, mindata, &maxwait, &poll) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_set_stream_poll"); goto faildetach; @@ -869,6 +912,7 @@ static int dag_activate(pcap_t* p) #endif if(dag_start_stream(p->fd, pd->dag_stream) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "dag_start_stream %s", device); goto faildetach; @@ -904,7 +948,8 @@ static int dag_activate(pcap_t* p) if ((n = atoi(s)) == 0 || n == 16 || n == 32) { pd->dag_fcs_bits = n; } else { - pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + ret = PCAP_ERROR; + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment", device, n); goto failstop; } @@ -914,7 +959,7 @@ static int dag_activate(pcap_t* p) * Did the user request that they not be stripped? */ if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) { - /* Yes. Note the number of bytes that will be + /* Yes. Note the number of 16-bit words that will be supplied. */ p->linktype_ext = LT_FCS_DATALINK_EXT(pd->dag_fcs_bits/16); @@ -926,12 +971,15 @@ static int dag_activate(pcap_t* p) pd->dag_timeout = p->opt.timeout; p->linktype = -1; - if (dag_get_datalink(p) < 0) + if (dag_get_datalink(p) < 0) { + ret = PCAP_ERROR; goto failstop; + } p->bufsize = 0; if (new_pcap_dag(p) < 0) { + ret = PCAP_ERROR; pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, errno, "new_pcap_dag %s", device); goto failstop; @@ -948,7 +996,7 @@ static int dag_activate(pcap_t* p) p->read_op = dag_read; p->inject_op = dag_inject; - p->setfilter_op = dag_setfilter; + p->setfilter_op = install_bpf_program; p->setdirection_op = NULL; /* Not implemented.*/ p->set_datalink_op = dag_set_datalink; p->getnonblock_op = pcap_getnonblock_fd; @@ -971,6 +1019,14 @@ faildetach: failclose: dag_config_dispose(pd->dag_ref); + /* + * Note: we don't need to call close(p->fd) or dag_close(p->fd), + * as dag_config_dispose(pd->dag_ref) does this. + * + * Set p->fd to -1 to make sure that's not done. + */ + p->fd = -1; + pd->dag_ref = NULL; delete_pcap_dag(p); fail: @@ -979,7 +1035,7 @@ fail: free((char *)newDev); } - return PCAP_ERROR; + return ret; } pcap_t *dag_create(const char *device, char *ebuf, int *is_ours) @@ -1029,7 +1085,7 @@ pcap_t *dag_create(const char *device, char *ebuf, int *is_ours) /* OK, it's probably ours. */ *is_ours = 1; - p = pcap_create_common(ebuf, sizeof (struct pcap_dag)); + p = PCAP_CREATE_COMMON(ebuf, struct pcap_dag); if (p == NULL) return NULL; @@ -1042,7 +1098,6 @@ pcap_t *dag_create(const char *device, char *ebuf, int *is_ours) * XXX Our native precision is 2^-32s, but libpcap doesn't support * power of two precisions yet. We can convert to either MICRO or NANO. */ - p->tstamp_precision_count = 2; p->tstamp_precision_list = malloc(2 * sizeof(u_int)); if (p->tstamp_precision_list == NULL) { pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, @@ -1052,18 +1107,35 @@ pcap_t *dag_create(const char *device, char *ebuf, int *is_ours) } p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; + p->tstamp_precision_count = 2; return p; } static int dag_stats(pcap_t *p, struct pcap_stat *ps) { struct pcap_dag *pd = p->priv; + uint32_t stream_drop; + dag_err_t dag_error; - /* This needs to be filled out correctly. Hopefully a dagapi call will - provide all necessary information. - */ - /*pd->stat.ps_recv = 0;*/ - /*pd->stat.ps_drop = 0;*/ + /* + * Packet records received (ps_recv) are counted in dag_read(). + * Packet records dropped (ps_drop) are read from Stream Drop attribute if present, + * otherwise integrate the ERF Header lctr counts (if available) in dag_read(). + * We are reporting that no records are dropped by the card/driver (ps_ifdrop). + */ + + if(pd->drop_attr != kNullAttributeUuid) { + /* Note this counter is cleared at start of capture and will wrap at UINT_MAX. + * The application is responsible for polling ps_drop frequently enough + * to detect each wrap and integrate total drop with a wider counter */ + if ((dag_error = dag_config_get_uint32_attribute_ex(pd->dag_ref, pd->drop_attr, &stream_drop)) == kDagErrNone) { + pd->stat.ps_drop = stream_drop; + } else { + snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "reading stream drop attribute: %s", + dag_config_strerror(dag_error)); + return -1; + } + } *ps = pd->stat; @@ -1087,10 +1159,10 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf) /* Try all the DAGs 0-DAG_MAX_BOARDS */ for (c = 0; c < DAG_MAX_BOARDS; c++) { - pcap_snprintf(name, 12, "dag%d", c); + snprintf(name, 12, "dag%d", c); if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream)) { - (void) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + (void) snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag: device name %s can't be parsed", name); return (-1); } @@ -1115,10 +1187,10 @@ dag_findalldevs(pcap_if_list_t *devlistp, char *errbuf) } rxstreams = dag_rx_get_stream_count(dagfd); for(stream=0;streamerrbuf, "setfilter: No filter specified", - sizeof(p->errbuf)); - return -1; - } - - /* Make our private copy of the filter */ - - if (install_bpf_program(p, fp) < 0) - return -1; - - return (0); -} - static int dag_set_datalink(pcap_t *p, int dlt) { @@ -1392,7 +1440,7 @@ pcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf) pcap_t * pcap_create_interface(const char *device, char *errbuf) { - pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + snprintf(errbuf, PCAP_ERRBUF_SIZE, "This version of libpcap only supports DAG cards"); return NULL; }