pcap-dag.c revision 127664
12973Sjlahoda/* 22973Sjlahoda * pcap-dag.c: Packet capture interface for Endace DAG card. 32973Sjlahoda * 42973Sjlahoda * The functionality of this code attempts to mimic that of pcap-linux as much 52973Sjlahoda * as possible. This code is compiled in several different ways depending on 62973Sjlahoda * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not 72973Sjlahoda * defined it should not get compiled in, otherwise if DAG_ONLY is defined then 82973Sjlahoda * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY 92973Sjlahoda * is not defined then nothing is altered - the dag_ functions will be 102973Sjlahoda * called as required from their pcap-linux/bpf equivalents. 112973Sjlahoda * 122973Sjlahoda * Author: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) 132973Sjlahoda * 142973Sjlahoda * Modifications: 152973Sjlahoda * 2003 May - Jesper Peterson <support@endace.com> 162973Sjlahoda * Code shuffled around to suit fad-xxx.c structure 172973Sjlahoda * Added atexit() handler to stop DAG if application is too lazy 182973Sjlahoda * 2003 September - Koryn Grant <koryn@endace.com> 192973Sjlahoda * Added support for nonblocking operation. 202973Sjlahoda * Added support for processing more than a single packet in pcap_dispatch(). 212973Sjlahoda * Fixed bug in loss counter code. 222973Sjlahoda * Improved portability of loss counter code (e.g. use UINT_MAX instead of 0xffff). 232973Sjlahoda * Removed unused local variables. 242973Sjlahoda * Added required headers (ctype.h, limits.h, unistd.h, netinet/in.h). 252973Sjlahoda * 2003 October - Koryn Grant <koryn@endace.com.> 262973Sjlahoda * Changed semantics to match those of standard pcap on linux. 272973Sjlahoda * - packets rejected by the filter are not counted. 282973Sjlahoda */ 292973Sjlahoda 302973Sjlahoda#ifndef lint 312973Sjlahodastatic const char rcsid[] _U_ = 322973Sjlahoda "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.10.2.4 2003/11/21 10:20:45 guy Exp $ (LBL)"; 332973Sjlahoda#endif 342973Sjlahoda 352973Sjlahoda#ifdef HAVE_CONFIG_H 362973Sjlahoda#include "config.h" 372973Sjlahoda#endif 382973Sjlahoda 392973Sjlahoda#include <sys/param.h> /* optionally get BSD define */ 402973Sjlahoda 412973Sjlahoda#include <stdlib.h> 422973Sjlahoda#include <string.h> 432973Sjlahoda#include <errno.h> 442973Sjlahoda 452973Sjlahoda#include "pcap-int.h" 462973Sjlahoda 472973Sjlahoda#include <ctype.h> 482973Sjlahoda#include <netinet/in.h> 492973Sjlahoda#include <sys/mman.h> 502973Sjlahoda#include <sys/socket.h> 512973Sjlahoda#include <sys/types.h> 522973Sjlahoda#include <unistd.h> 532973Sjlahoda 542973Sjlahodastruct mbuf; /* Squelch compiler warnings on some platforms for */ 552973Sjlahodastruct rtentry; /* declarations in <net/if.h> */ 562973Sjlahoda#include <net/if.h> 572973Sjlahoda 582973Sjlahoda#include <dagnew.h> 592973Sjlahoda#include <dagapi.h> 602973Sjlahoda 612973Sjlahoda#define MIN_DAG_SNAPLEN 12 622973Sjlahoda#define MAX_DAG_SNAPLEN 2040 632973Sjlahoda#define ATM_SNAPLEN 48 642973Sjlahoda 652973Sjlahodatypedef struct pcap_dag_node { 662973Sjlahoda struct pcap_dag_node *next; 672973Sjlahoda pcap_t *p; 682973Sjlahoda pid_t pid; 692973Sjlahoda} pcap_dag_node_t; 702973Sjlahoda 712973Sjlahodastatic pcap_dag_node_t *pcap_dags = NULL; 722973Sjlahodastatic int atexit_handler_installed = 0; 732973Sjlahodastatic const unsigned short endian_test_word = 0x0100; 742973Sjlahoda 752973Sjlahoda#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) 762973Sjlahoda 772973Sjlahoda/* 782973Sjlahoda * Swap byte ordering of unsigned long long timestamp on a big endian 792973Sjlahoda * machine. 802973Sjlahoda */ 812973Sjlahoda#define SWAP_TS(ull) ((ull & 0xff00000000000000LL) >> 56) | \ 822973Sjlahoda ((ull & 0x00ff000000000000LL) >> 40) | \ 832973Sjlahoda ((ull & 0x0000ff0000000000LL) >> 24) | \ 842973Sjlahoda ((ull & 0x000000ff00000000LL) >> 8) | \ 852973Sjlahoda ((ull & 0x00000000ff000000LL) << 8) | \ 862973Sjlahoda ((ull & 0x0000000000ff0000LL) << 24) | \ 872973Sjlahoda ((ull & 0x000000000000ff00LL) << 40) | \ 882973Sjlahoda ((ull & 0x00000000000000ffLL) << 56) 892973Sjlahoda 902973Sjlahoda 912973Sjlahoda#ifdef DAG_ONLY 922973Sjlahoda/* This code is required when compiling for a DAG device only. */ 932973Sjlahoda#include "pcap-dag.h" 942973Sjlahoda 952973Sjlahoda/* Replace dag function names with pcap equivalent. */ 962973Sjlahoda#define dag_open_live pcap_open_live 972973Sjlahoda#define dag_platform_finddevs pcap_platform_finddevs 982973Sjlahoda#endif /* DAG_ONLY */ 992973Sjlahoda 1002973Sjlahodastatic int dag_setfilter(pcap_t *p, struct bpf_program *fp); 1012973Sjlahodastatic int dag_stats(pcap_t *p, struct pcap_stat *ps); 1022973Sjlahodastatic int dag_set_datalink(pcap_t *p, int dlt); 1032973Sjlahodastatic int dag_get_datalink(pcap_t *p); 1042973Sjlahodastatic int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf); 1052973Sjlahoda 1062973Sjlahodastatic void delete_pcap_dag(pcap_t *p) { 1072973Sjlahoda pcap_dag_node_t *curr = NULL, *prev = NULL; 1082973Sjlahoda 1092973Sjlahoda for (prev = NULL, curr = pcap_dags; 1102973Sjlahoda curr != NULL && curr->p != p; 1112973Sjlahoda prev = curr, curr = curr->next) { 1122973Sjlahoda /* empty */ 1132973Sjlahoda } 1142973Sjlahoda 1152973Sjlahoda if (curr != NULL && curr->p == p) { 1162973Sjlahoda if (prev != NULL) { 1172973Sjlahoda prev->next = curr->next; 1182973Sjlahoda } else { 1192973Sjlahoda pcap_dags = curr->next; 1202973Sjlahoda } 1212973Sjlahoda } 1222973Sjlahoda} 1232973Sjlahoda 1242973Sjlahoda/* 1252973Sjlahoda * Performs a graceful shutdown of the DAG card, frees dynamic memory held 1262973Sjlahoda * in the pcap_t structure, and closes the file descriptor for the DAG card. 1272973Sjlahoda */ 1282973Sjlahoda 1292973Sjlahodastatic void dag_platform_close(pcap_t *p) { 1302973Sjlahoda 1312973Sjlahoda#ifdef linux 1322973Sjlahoda if (p != NULL && p->md.device != NULL) { 1332973Sjlahoda if(dag_stop(p->fd) < 0) 1342973Sjlahoda fprintf(stderr,"dag_stop %s: %s\n", p->md.device, strerror(errno)); 1352973Sjlahoda if(dag_close(p->fd) < 0) 1362973Sjlahoda fprintf(stderr,"dag_close %s: %s\n", p->md.device, strerror(errno)); 1372973Sjlahoda 1382973Sjlahoda free(p->md.device); 1392973Sjlahoda } 1402973Sjlahoda#else 1412973Sjlahoda if (p != NULL) { 1422973Sjlahoda if(dag_stop(p->fd) < 0) 1432973Sjlahoda fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 1442973Sjlahoda if(dag_close(p->fd) < 0) 1452973Sjlahoda fprintf(stderr,"dag_close: %s\n", strerror(errno)); 1462973Sjlahoda } 1472973Sjlahoda#endif 1482973Sjlahoda delete_pcap_dag(p); 1492973Sjlahoda /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ 1502973Sjlahoda} 1512973Sjlahoda 1522973Sjlahodastatic void atexit_handler(void) { 1532973Sjlahoda while (pcap_dags != NULL) { 1542973Sjlahoda if (pcap_dags->pid == getpid()) { 1552973Sjlahoda dag_platform_close(pcap_dags->p); 1562973Sjlahoda } else { 1572973Sjlahoda delete_pcap_dag(pcap_dags->p); 1582973Sjlahoda } 1592973Sjlahoda } 1602973Sjlahoda} 1612973Sjlahoda 1622973Sjlahodastatic int new_pcap_dag(pcap_t *p) { 1632973Sjlahoda pcap_dag_node_t *node = NULL; 1642973Sjlahoda 1652973Sjlahoda if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { 1662973Sjlahoda return -1; 1672973Sjlahoda } 1682973Sjlahoda 1692973Sjlahoda if (!atexit_handler_installed) { 1702973Sjlahoda atexit(atexit_handler); 1712973Sjlahoda atexit_handler_installed = 1; 1722973Sjlahoda } 1732973Sjlahoda 1742973Sjlahoda node->next = pcap_dags; 1752973Sjlahoda node->p = p; 1762973Sjlahoda node->pid = getpid(); 1772973Sjlahoda 1782973Sjlahoda pcap_dags = node; 1792973Sjlahoda 1802973Sjlahoda return 0; 1812973Sjlahoda} 1822973Sjlahoda 1832973Sjlahoda/* 1842973Sjlahoda * Read at most max_packets from the capture stream and call the callback 1852973Sjlahoda * for each of them. Returns the number of packets handled, -1 if an 1862973Sjlahoda * error occured, or -2 if we were told to break out of the loop. 1872973Sjlahoda */ 1882973Sjlahodastatic int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { 1892973Sjlahoda unsigned int processed = 0; 1902973Sjlahoda int flags = p->md.dag_offset_flags; 1912973Sjlahoda unsigned int nonblocking = flags & DAGF_NONBLOCK; 1922973Sjlahoda 1932973Sjlahoda for (;;) 1942973Sjlahoda { 1952973Sjlahoda /* Get the next bufferful of packets (if necessary). */ 1962973Sjlahoda while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) { 1972973Sjlahoda 1982973Sjlahoda /* 1992973Sjlahoda * Has "pcap_breakloop()" been called? 2002973Sjlahoda */ 2012973Sjlahoda if (p->break_loop) { 2022973Sjlahoda /* 2032973Sjlahoda * Yes - clear the flag that indicates that 2042973Sjlahoda * it has, and return -2 to indicate that 2052973Sjlahoda * we were told to break out of the loop. 2062973Sjlahoda */ 2072973Sjlahoda p->break_loop = 0; 2082973Sjlahoda return -2; 2092973Sjlahoda } 2102973Sjlahoda 2112973Sjlahoda p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), flags); 2122973Sjlahoda if ((p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) && nonblocking) 2132973Sjlahoda { 2142973Sjlahoda /* Pcap is configured to process only available packets, and there aren't any. */ 2152973Sjlahoda return 0; 2162973Sjlahoda } 2172973Sjlahoda } 2182973Sjlahoda 2192973Sjlahoda /* Process the packets. */ 2202973Sjlahoda while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) { 2212973Sjlahoda 2222973Sjlahoda unsigned short packet_len = 0; 2232973Sjlahoda int caplen = 0; 2242973Sjlahoda struct pcap_pkthdr pcap_header; 2252973Sjlahoda 2262973Sjlahoda dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom); 2272973Sjlahoda u_char *dp = ((u_char *)header) + dag_record_size; 2282973Sjlahoda unsigned short rlen; 2292973Sjlahoda 2302973Sjlahoda /* 2312973Sjlahoda * Has "pcap_breakloop()" been called? 2322973Sjlahoda */ 2332973Sjlahoda if (p->break_loop) { 2342973Sjlahoda /* 2352973Sjlahoda * Yes - clear the flag that indicates that 2362973Sjlahoda * it has, and return -2 to indicate that 2372973Sjlahoda * we were told to break out of the loop. 2382973Sjlahoda */ 2392973Sjlahoda p->break_loop = 0; 2402973Sjlahoda return -2; 2412973Sjlahoda } 2422973Sjlahoda 2432973Sjlahoda if (IS_BIGENDIAN()) 2442973Sjlahoda { 2452973Sjlahoda rlen = header->rlen; 2462973Sjlahoda } 2472973Sjlahoda else 2482973Sjlahoda { 2492973Sjlahoda rlen = ntohs(header->rlen); 2502973Sjlahoda } 2512973Sjlahoda p->md.dag_mem_bottom += rlen; 2522973Sjlahoda 2532973Sjlahoda switch(header->type) { 2542973Sjlahoda case TYPE_ATM: 2552973Sjlahoda packet_len = ATM_SNAPLEN; 2562973Sjlahoda caplen = ATM_SNAPLEN; 2572973Sjlahoda dp += 4; 2582973Sjlahoda break; 2592973Sjlahoda 2602973Sjlahoda case TYPE_ETH: 2612973Sjlahoda if (IS_BIGENDIAN()) 2622973Sjlahoda { 2632973Sjlahoda packet_len = header->wlen; 2642973Sjlahoda } 2652973Sjlahoda else 2662973Sjlahoda { 2672973Sjlahoda packet_len = ntohs(header->wlen); 2682973Sjlahoda } 2692973Sjlahoda packet_len -= (p->md.dag_fcs_bits >> 3); 2702973Sjlahoda caplen = rlen - dag_record_size - 2; 2712973Sjlahoda if (caplen > packet_len) 2722973Sjlahoda { 2732973Sjlahoda caplen = packet_len; 2742973Sjlahoda } 2752973Sjlahoda dp += 2; 2762973Sjlahoda break; 2772973Sjlahoda 2782973Sjlahoda case TYPE_HDLC_POS: 2792973Sjlahoda if (IS_BIGENDIAN()) 2802973Sjlahoda { 2812973Sjlahoda packet_len = header->wlen; 2822973Sjlahoda } 2832973Sjlahoda else 2842973Sjlahoda { 2852973Sjlahoda packet_len = ntohs(header->wlen); 2862973Sjlahoda } 2872973Sjlahoda packet_len -= (p->md.dag_fcs_bits >> 3); 2882973Sjlahoda caplen = rlen - dag_record_size; 2892973Sjlahoda if (caplen > packet_len) 2902973Sjlahoda { 2912973Sjlahoda caplen = packet_len; 2922973Sjlahoda } 2932973Sjlahoda break; 2942973Sjlahoda } 2952973Sjlahoda 2962973Sjlahoda if (caplen > p->snapshot) 2972973Sjlahoda caplen = p->snapshot; 2982973Sjlahoda 2992973Sjlahoda /* Count lost packets. */ 3002973Sjlahoda if (header->lctr) { 3012973Sjlahoda if (p->md.stat.ps_drop > (UINT_MAX - header->lctr)) { 3022973Sjlahoda p->md.stat.ps_drop = UINT_MAX; 3032973Sjlahoda } else { 3042973Sjlahoda p->md.stat.ps_drop += header->lctr; 3052973Sjlahoda } 3062973Sjlahoda } 3072973Sjlahoda 3082973Sjlahoda /* Run the packet filter if there is one. */ 3092973Sjlahoda if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { 3102973Sjlahoda 3112973Sjlahoda /* convert between timestamp formats */ 3122973Sjlahoda register unsigned long long ts; 3132973Sjlahoda 3142973Sjlahoda if (IS_BIGENDIAN()) 3152973Sjlahoda { 3162973Sjlahoda ts = SWAP_TS(header->ts); 3172973Sjlahoda } 3182973Sjlahoda else 3192973Sjlahoda { 3202973Sjlahoda ts = header->ts; 3212973Sjlahoda } 3222973Sjlahoda 3232973Sjlahoda pcap_header.ts.tv_sec = ts >> 32; 3242973Sjlahoda ts = (ts & 0xffffffffULL) * 1000000; 3252973Sjlahoda ts += 0x80000000; /* rounding */ 3262973Sjlahoda pcap_header.ts.tv_usec = ts >> 32; 3272973Sjlahoda if (pcap_header.ts.tv_usec >= 1000000) { 3282973Sjlahoda pcap_header.ts.tv_usec -= 1000000; 3292973Sjlahoda pcap_header.ts.tv_sec++; 3302973Sjlahoda } 3312973Sjlahoda 3322973Sjlahoda /* Fill in our own header data */ 3332973Sjlahoda pcap_header.caplen = caplen; 3342973Sjlahoda pcap_header.len = packet_len; 3352973Sjlahoda 3362973Sjlahoda /* Count the packet. */ 3372973Sjlahoda p->md.stat.ps_recv++; 3382973Sjlahoda 3392973Sjlahoda /* Call the user supplied callback function */ 3402973Sjlahoda callback(user, &pcap_header, dp); 3412973Sjlahoda 3422973Sjlahoda /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ 3432973Sjlahoda processed++; 3442973Sjlahoda if (processed == cnt) 3452973Sjlahoda { 3462973Sjlahoda /* Reached the user-specified limit. */ 3472973Sjlahoda return cnt; 3482973Sjlahoda } 3492973Sjlahoda } 3502973Sjlahoda } 3512973Sjlahoda 3522973Sjlahoda if (nonblocking || processed) 3532973Sjlahoda { 3542973Sjlahoda return processed; 3552973Sjlahoda } 3562973Sjlahoda } 3572973Sjlahoda 3582973Sjlahoda return processed; 3592973Sjlahoda} 3602973Sjlahoda 3612973Sjlahoda/* 3622973Sjlahoda * Get a handle for a live capture from the given DAG device. Passing a NULL 3632973Sjlahoda * device will result in a failure. The promisc flag is ignored because DAG 3642973Sjlahoda * cards are always promiscuous. The to_ms parameter is also ignored as it is 3652973Sjlahoda * not supported in hardware. 3662973Sjlahoda * 3672973Sjlahoda * See also pcap(3). 3682973Sjlahoda */ 3692973Sjlahodapcap_t *dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf) { 3702973Sjlahoda char conf[30]; /* dag configure string */ 3712973Sjlahoda pcap_t *handle; 3722973Sjlahoda char *s; 3732973Sjlahoda int n; 3742973Sjlahoda 3752973Sjlahoda if (device == NULL) { 3762973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); 3772973Sjlahoda return NULL; 3782973Sjlahoda } 3792973Sjlahoda /* Allocate a handle for this session. */ 3802973Sjlahoda 3812973Sjlahoda handle = malloc(sizeof(*handle)); 3822973Sjlahoda if (handle == NULL) { 3832973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc %s: %s", device, pcap_strerror(errno)); 3842973Sjlahoda return NULL; 3852973Sjlahoda } 3862973Sjlahoda 3872973Sjlahoda /* Initialize some components of the pcap structure. */ 3882973Sjlahoda 3892973Sjlahoda memset(handle, 0, sizeof(*handle)); 3902973Sjlahoda 3912973Sjlahoda if (strstr(device, "/dev") == NULL) { 3922973Sjlahoda char * newDev = (char *)malloc(strlen(device) + 6); 3932973Sjlahoda newDev[0] = '\0'; 3942973Sjlahoda strcat(newDev, "/dev/"); 3952973Sjlahoda strcat(newDev,device); 3962973Sjlahoda device = newDev; 3972973Sjlahoda } else { 3982973Sjlahoda device = strdup(device); 3992973Sjlahoda } 4002973Sjlahoda 4012973Sjlahoda if (device == NULL) { 4022973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE, "str_dup: %s\n", pcap_strerror(errno)); 4032973Sjlahoda goto fail; 4042973Sjlahoda } 4052973Sjlahoda 4062973Sjlahoda /* setup device parameters */ 4072973Sjlahoda if((handle->fd = dag_open((char *)device)) < 0) { 4082973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno)); 4092973Sjlahoda goto fail; 4102973Sjlahoda } 4112973Sjlahoda 4122973Sjlahoda /* set the card snap length to the specified snaplen parameter */ 4132973Sjlahoda if (snaplen == 0 || snaplen > MAX_DAG_SNAPLEN) { 4142973Sjlahoda snaplen = MAX_DAG_SNAPLEN; 4152973Sjlahoda } else if (snaplen < MIN_DAG_SNAPLEN) { 4162973Sjlahoda snaplen = MIN_DAG_SNAPLEN; 4172973Sjlahoda } 4182973Sjlahoda /* snap len has to be a multiple of 4 */ 4192973Sjlahoda snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); 4202973Sjlahoda 4212973Sjlahoda fprintf(stderr, "Configuring DAG with '%s'.\n", conf); 4222973Sjlahoda if(dag_configure(handle->fd, conf) < 0) { 4232973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno)); 4242973Sjlahoda goto fail; 4252973Sjlahoda } 4262973Sjlahoda 4272973Sjlahoda if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { 4282973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno)); 4292973Sjlahoda goto fail; 4302973Sjlahoda } 4312973Sjlahoda 4322973Sjlahoda if(dag_start(handle->fd) < 0) { 4332973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno)); 4342973Sjlahoda goto fail; 4352973Sjlahoda } 4362973Sjlahoda 4372973Sjlahoda /* 4382973Sjlahoda * Important! You have to ensure bottom is properly 4392973Sjlahoda * initialized to zero on startup, it won't give you 4402973Sjlahoda * a compiler warning if you make this mistake! 4412973Sjlahoda */ 4422973Sjlahoda handle->md.dag_mem_bottom = 0; 4432973Sjlahoda handle->md.dag_mem_top = 0; 4442973Sjlahoda 4452973Sjlahoda /* TODO: query the card */ 4462973Sjlahoda handle->md.dag_fcs_bits = 32; 4472973Sjlahoda if ((s = getenv("ERF_FCS_BITS")) != NULL) { 4482973Sjlahoda if ((n = atoi(s)) == 0 || n == 16|| n == 32) { 4492973Sjlahoda handle->md.dag_fcs_bits = n; 4502973Sjlahoda } else { 4512973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE, 4522973Sjlahoda "pcap_open_live %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n); 4532973Sjlahoda goto fail; 4542973Sjlahoda } 4552973Sjlahoda } 4562973Sjlahoda 4572973Sjlahoda handle->snapshot = snaplen; 4582973Sjlahoda /*handle->md.timeout = to_ms; */ 4592973Sjlahoda 4602973Sjlahoda if ((handle->linktype = dag_get_datalink(handle)) < 0) { 4612973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_get_linktype %s: unknown linktype\n", device); 4622973Sjlahoda goto fail; 4632973Sjlahoda } 4642973Sjlahoda 4652973Sjlahoda handle->bufsize = 0; 4662973Sjlahoda 4672973Sjlahoda if (new_pcap_dag(handle) < 0) { 4682973Sjlahoda snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno)); 4692973Sjlahoda goto fail; 4702973Sjlahoda } 4712973Sjlahoda 4722973Sjlahoda /* 4732973Sjlahoda * "select()" and "poll()" don't (yet) work on DAG device descriptors. 4742973Sjlahoda */ 4752973Sjlahoda handle->selectable_fd = -1; 4762973Sjlahoda 4772973Sjlahoda#ifdef linux 4782973Sjlahoda handle->md.device = (char *)device; 4792973Sjlahoda#else 4802973Sjlahoda free((char *)device); 4812973Sjlahoda device = NULL; 4822973Sjlahoda#endif 4832973Sjlahoda 4842973Sjlahoda handle->read_op = dag_read; 4852973Sjlahoda handle->setfilter_op = dag_setfilter; 4862973Sjlahoda handle->set_datalink_op = dag_set_datalink; 4872973Sjlahoda handle->getnonblock_op = pcap_getnonblock_fd; 4882973Sjlahoda handle->setnonblock_op = dag_setnonblock; 4892973Sjlahoda handle->stats_op = dag_stats; 4902973Sjlahoda handle->close_op = dag_platform_close; 4912973Sjlahoda 4922973Sjlahoda return handle; 4932973Sjlahoda 4942973Sjlahodafail: 4952973Sjlahoda if (device != NULL) { 4962973Sjlahoda free((char *)device); 4972973Sjlahoda } 4982973Sjlahoda if (handle != NULL) { 4992973Sjlahoda free(handle); 5002973Sjlahoda } 5012973Sjlahoda 5022973Sjlahoda return NULL; 5032973Sjlahoda} 5042973Sjlahoda 5052973Sjlahodastatic int dag_stats(pcap_t *p, struct pcap_stat *ps) { 5062973Sjlahoda /* This needs to be filled out correctly. Hopefully a dagapi call will 5072973Sjlahoda provide all necessary information. 5082973Sjlahoda */ 5092973Sjlahoda /*p->md.stat.ps_recv = 0;*/ 5102973Sjlahoda /*p->md.stat.ps_drop = 0;*/ 5112973Sjlahoda 5122973Sjlahoda *ps = p->md.stat; 5132973Sjlahoda 5142973Sjlahoda return 0; 5152973Sjlahoda} 5162973Sjlahoda 5172973Sjlahoda/* 5182973Sjlahoda * Get from "/proc/dag" all interfaces listed there; if they're 5192973Sjlahoda * already in the list of interfaces we have, that won't add another 5202973Sjlahoda * instance, but if they're not, that'll add them. 5212973Sjlahoda * 5222973Sjlahoda * We don't bother getting any addresses for them. 5232973Sjlahoda * 5242973Sjlahoda * We also don't fail if we couldn't open "/proc/dag"; we just leave 5252973Sjlahoda * the list of interfaces as is. 5262973Sjlahoda */ 5272973Sjlahodaint 5282973Sjlahodadag_platform_finddevs(pcap_if_t **devlistp, char *errbuf) 5292973Sjlahoda{ 5302973Sjlahoda FILE *proc_dag_f; 5312973Sjlahoda char linebuf[512]; 5322973Sjlahoda int linenum; 5332973Sjlahoda unsigned char *p; 5342973Sjlahoda char name[512]; /* XXX - pick a size */ 5352973Sjlahoda char *q; 5362973Sjlahoda int ret = 0; 5372973Sjlahoda 5382973Sjlahoda /* Quick exit if /proc/dag not readable */ 5392973Sjlahoda proc_dag_f = fopen("/proc/dag", "r"); 5402973Sjlahoda if (proc_dag_f == NULL) 5412973Sjlahoda { 5422973Sjlahoda int i; 5432973Sjlahoda char dev[16] = "dagx"; 5442973Sjlahoda 5452973Sjlahoda for (i = '0'; ret == 0 && i <= '9'; i++) { 5462973Sjlahoda dev[3] = i; 5472973Sjlahoda if (pcap_add_if(devlistp, dev, 0, NULL, errbuf) == -1) { 5482973Sjlahoda /* 5492973Sjlahoda * Failure. 5502973Sjlahoda */ 5512973Sjlahoda ret = -1; 5522973Sjlahoda } 5532973Sjlahoda } 5542973Sjlahoda 5552973Sjlahoda return (ret); 5562973Sjlahoda } 5572973Sjlahoda 5582973Sjlahoda for (linenum = 1; 5592973Sjlahoda fgets(linebuf, sizeof linebuf, proc_dag_f) != NULL; linenum++) { 5602973Sjlahoda 5612973Sjlahoda /* 5622973Sjlahoda * Skip the first two lines - they're headers. 5632973Sjlahoda */ 5642973Sjlahoda if (linenum <= 2) 5652973Sjlahoda continue; 5662973Sjlahoda 5672973Sjlahoda p = &linebuf[0]; 5682973Sjlahoda 5692973Sjlahoda if (*p == '\0' || *p == '\n' || *p != 'D') 5702973Sjlahoda continue; /* not a Dag line */ 5712973Sjlahoda 5722973Sjlahoda /* 5732973Sjlahoda * Get the interface name. 5742973Sjlahoda */ 5752973Sjlahoda q = &name[0]; 5762973Sjlahoda while (*p != '\0' && *p != ':') { 5772973Sjlahoda if (*p != ' ') 5782973Sjlahoda *q++ = tolower(*p++); 5792973Sjlahoda else 5802973Sjlahoda p++; 5812973Sjlahoda } 5822973Sjlahoda *q = '\0'; 5832973Sjlahoda 5842973Sjlahoda /* 5852973Sjlahoda * Add an entry for this interface, with no addresses. 5862973Sjlahoda */ 5872973Sjlahoda p[strlen(p) - 1] = '\0'; /* get rid of \n */ 5882973Sjlahoda if (pcap_add_if(devlistp, name, 0, strdup(p + 2), errbuf) == -1) { 5892973Sjlahoda /* 5902973Sjlahoda * Failure. 5912973Sjlahoda */ 5922973Sjlahoda ret = -1; 5932973Sjlahoda break; 5942973Sjlahoda } 5952973Sjlahoda } 5962973Sjlahoda if (ret != -1) { 5972973Sjlahoda /* 5982973Sjlahoda * Well, we didn't fail for any other reason; did we 5992973Sjlahoda * fail due to an error reading the file? 6002973Sjlahoda */ 6012973Sjlahoda if (ferror(proc_dag_f)) { 6022973Sjlahoda (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 6032973Sjlahoda "Error reading /proc/dag: %s", 6042973Sjlahoda pcap_strerror(errno)); 6052973Sjlahoda ret = -1; 6062973Sjlahoda } 6072973Sjlahoda } 6082973Sjlahoda 6092973Sjlahoda (void)fclose(proc_dag_f); 6102973Sjlahoda return (ret); 6112973Sjlahoda} 6122973Sjlahoda 6132973Sjlahoda/* 6142973Sjlahoda * Installs the given bpf filter program in the given pcap structure. There is 6152973Sjlahoda * no attempt to store the filter in kernel memory as that is not supported 6162973Sjlahoda * with DAG cards. 6172973Sjlahoda */ 6182973Sjlahodastatic int dag_setfilter(pcap_t *p, struct bpf_program *fp) { 6192973Sjlahoda if (!p) 6202973Sjlahoda return -1; 6212973Sjlahoda if (!fp) { 6222973Sjlahoda strncpy(p->errbuf, "setfilter: No filter specified", 6232973Sjlahoda sizeof(p->errbuf)); 6242973Sjlahoda return -1; 6252973Sjlahoda } 6262973Sjlahoda 6272973Sjlahoda /* Make our private copy of the filter */ 6282973Sjlahoda 6292973Sjlahoda if (install_bpf_program(p, fp) < 0) { 6302973Sjlahoda snprintf(p->errbuf, sizeof(p->errbuf), 6312973Sjlahoda "malloc: %s", pcap_strerror(errno)); 6322973Sjlahoda return -1; 6332973Sjlahoda } 6342973Sjlahoda 6352973Sjlahoda p->md.use_bpf = 0; 6362973Sjlahoda 6372973Sjlahoda return (0); 6382973Sjlahoda} 6392973Sjlahoda 6402973Sjlahodastatic int 6412973Sjlahodadag_set_datalink(pcap_t *p, int dlt) 6422973Sjlahoda{ 6432973Sjlahoda return (0); 6442973Sjlahoda} 6452973Sjlahoda 6462973Sjlahodastatic int 6472973Sjlahodadag_setnonblock(pcap_t *p, int nonblock, char *errbuf) 6482973Sjlahoda{ 6492973Sjlahoda /* 6502973Sjlahoda * Set non-blocking mode on the FD. 6512973Sjlahoda * XXX - is that necessary? If not, don't bother calling it, 6522973Sjlahoda * and have a "dag_getnonblock()" function that looks at 6532973Sjlahoda * "p->md.dag_offset_flags". 6542973Sjlahoda */ 6552973Sjlahoda if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0) 6562973Sjlahoda return (-1); 6572973Sjlahoda 6582973Sjlahoda if (nonblock) { 6592973Sjlahoda p->md.dag_offset_flags |= DAGF_NONBLOCK; 6602973Sjlahoda } else { 6612973Sjlahoda p->md.dag_offset_flags &= ~DAGF_NONBLOCK; 6622973Sjlahoda } 6632973Sjlahoda return (0); 6642973Sjlahoda} 6652973Sjlahoda 6662973Sjlahodastatic int 6672973Sjlahodadag_get_datalink(pcap_t *p) 6682973Sjlahoda{ 6692973Sjlahoda int linktype = -1; 6702973Sjlahoda 6712973Sjlahoda /* Check the type through a dagapi call. 6722973Sjlahoda */ 6732973Sjlahoda switch(dag_linktype(p->fd)) { 6742973Sjlahoda case TYPE_HDLC_POS: { 6752973Sjlahoda dag_record_t *record; 676 677 /* peek at the first available record to see if it is PPP */ 678 while ((p->md.dag_mem_top - p->md.dag_mem_bottom) < (dag_record_size + 4)) { 679 p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), 0); 680 } 681 record = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom); 682 683 if ((ntohl(record->rec.pos.hdlc) & 0xffff0000) == 0xff030000) { 684 linktype = DLT_PPP_SERIAL; 685 fprintf(stderr, "Set DAG linktype to %d (DLT_PPP_SERIAL)\n", linktype); 686 } else { 687 linktype = DLT_CHDLC; 688 fprintf(stderr, "Set DAG linktype to %d (DLT_CHDLC)\n", linktype); 689 } 690 break; 691 } 692 case TYPE_ETH: 693 linktype = DLT_EN10MB; 694 fprintf(stderr, "Set DAG linktype to %d (DLT_EN10MB)\n", linktype); 695 break; 696 case TYPE_ATM: 697 linktype = DLT_ATM_RFC1483; 698 fprintf(stderr, "Set DAG linktype to %d (DLT_ATM_RFC1483)\n", linktype); 699 break; 700 case TYPE_LEGACY: 701 linktype = DLT_NULL; 702 fprintf(stderr, "Set DAG linktype to %d (DLT_NULL)\n", linktype); 703 break; 704 default: 705 fprintf(stderr, "Unknown DAG linktype %d\n", dag_linktype(p->fd)); 706 break; 707 } 708 709 return linktype; 710} 711