pcap-dag.c revision 147894
1231990Smp/* 259243Sobrien * pcap-dag.c: Packet capture interface for Endace DAG card. 359243Sobrien * 459243Sobrien * The functionality of this code attempts to mimic that of pcap-linux as much 559243Sobrien * as possible. This code is compiled in several different ways depending on 659243Sobrien * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not 759243Sobrien * defined it should not get compiled in, otherwise if DAG_ONLY is defined then 859243Sobrien * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY 959243Sobrien * is not defined then nothing is altered - the dag_ functions will be 1059243Sobrien * called as required from their pcap-linux/bpf equivalents. 1159243Sobrien * 1259243Sobrien * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) 1359243Sobrien * Modifications: Jesper Peterson, Koryn Grant <support@endace.com> 1459243Sobrien */ 1559243Sobrien 1659243Sobrien#ifndef lint 17100616Smpstatic const char rcsid[] _U_ = 1859243Sobrien "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.21.2.1 2005/05/03 18:54:35 guy Exp $ (LBL)"; 1959243Sobrien#endif 2059243Sobrien 2159243Sobrien#ifdef HAVE_CONFIG_H 2259243Sobrien#include "config.h" 2359243Sobrien#endif 2459243Sobrien 2559243Sobrien#include <sys/param.h> /* optionally get BSD define */ 2659243Sobrien 2759243Sobrien#include <stdlib.h> 2859243Sobrien#include <string.h> 2959243Sobrien#include <errno.h> 3059243Sobrien 3159243Sobrien#include "pcap-int.h" 3259243Sobrien 3359243Sobrien#include <ctype.h> 3459243Sobrien#include <netinet/in.h> 35231990Smp#include <sys/mman.h> 3659243Sobrien#include <sys/socket.h> 3759243Sobrien#include <sys/types.h> 3859243Sobrien#include <unistd.h> 3959243Sobrien 4059243Sobrienstruct mbuf; /* Squelch compiler warnings on some platforms for */ 4159243Sobrienstruct rtentry; /* declarations in <net/if.h> */ 4259243Sobrien#include <net/if.h> 4359243Sobrien 4459243Sobrien#include "dagnew.h" 4559243Sobrien#include "dagapi.h" 46231990Smp 4759243Sobrien#define MIN_DAG_SNAPLEN 12 4859243Sobrien#define MAX_DAG_SNAPLEN 2040 4959243Sobrien#define ATM_CELL_SIZE 52 50184072Sru#define ATM_HDR_SIZE 4 5159243Sobrien 5259243Sobrien/* SunATM pseudo header */ 5359243Sobrienstruct sunatm_hdr { 5459243Sobrien unsigned char flags; /* destination and traffic type */ 5559243Sobrien unsigned char vpi; /* VPI */ 5659243Sobrien unsigned short vci; /* VCI */ 5759243Sobrien}; 5859243Sobrien 5959243Sobrientypedef struct pcap_dag_node { 6059243Sobrien struct pcap_dag_node *next; 6159243Sobrien pcap_t *p; 6259243Sobrien pid_t pid; 6359243Sobrien} pcap_dag_node_t; 64231990Smp 6559243Sobrienstatic pcap_dag_node_t *pcap_dags = NULL; 6659243Sobrienstatic int atexit_handler_installed = 0; 6759243Sobrienstatic const unsigned short endian_test_word = 0x0100; 6859243Sobrien 6959243Sobrien#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) 7059243Sobrien 7159243Sobrien/* 72231990Smp * Swap byte ordering of unsigned long long timestamp on a big endian 7359243Sobrien * machine. 7459243Sobrien */ 7559243Sobrien#define SWAP_TS(ull) ((ull & 0xff00000000000000LL) >> 56) | \ 7659243Sobrien ((ull & 0x00ff000000000000LL) >> 40) | \ 7759243Sobrien ((ull & 0x0000ff0000000000LL) >> 24) | \ 7859243Sobrien ((ull & 0x000000ff00000000LL) >> 8) | \ 7959243Sobrien ((ull & 0x00000000ff000000LL) << 8) | \ 8059243Sobrien ((ull & 0x0000000000ff0000LL) << 24) | \ 8159243Sobrien ((ull & 0x000000000000ff00LL) << 40) | \ 8259243Sobrien ((ull & 0x00000000000000ffLL) << 56) 8359243Sobrien 8459243Sobrien 8559243Sobrien#ifdef DAG_ONLY 8659243Sobrien/* This code is required when compiling for a DAG device only. */ 8759243Sobrien#include "pcap-dag.h" 8859243Sobrien 8959243Sobrien/* Replace dag function names with pcap equivalent. */ 90145479Smp#define dag_open_live pcap_open_live 91145479Smp#define dag_platform_finddevs pcap_platform_finddevs 9259243Sobrien#endif /* DAG_ONLY */ 9359243Sobrien 9459243Sobrienstatic int dag_setfilter(pcap_t *p, struct bpf_program *fp); 9559243Sobrienstatic int dag_stats(pcap_t *p, struct pcap_stat *ps); 9659243Sobrienstatic int dag_set_datalink(pcap_t *p, int dlt); 9759243Sobrienstatic int dag_get_datalink(pcap_t *p); 9859243Sobrienstatic int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf); 9959243Sobrien 10059243Sobrienstatic void 10159243Sobriendelete_pcap_dag(pcap_t *p) 10259243Sobrien{ 10359243Sobrien pcap_dag_node_t *curr = NULL, *prev = NULL; 10459243Sobrien 10559243Sobrien for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { 10659243Sobrien /* empty */ 10759243Sobrien } 10859243Sobrien 10959243Sobrien if (curr != NULL && curr->p == p) { 11059243Sobrien if (prev != NULL) { 11159243Sobrien prev->next = curr->next; 11259243Sobrien } else { 11359243Sobrien pcap_dags = curr->next; 11459243Sobrien } 11559243Sobrien } 11659243Sobrien} 11759243Sobrien 11859243Sobrien/* 11969408Sache * Performs a graceful shutdown of the DAG card, frees dynamic memory held 12069408Sache * in the pcap_t structure, and closes the file descriptor for the DAG card. 121100616Smp */ 12269408Sache 12359243Sobrienstatic void 12459243Sobriendag_platform_close(pcap_t *p) 12559243Sobrien{ 12659243Sobrien 127131962Smp#ifdef linux 128131962Smp if (p != NULL && p->md.device != NULL) { 129131962Smp if(dag_stop(p->fd) < 0) 13059243Sobrien fprintf(stderr,"dag_stop %s: %s\n", p->md.device, strerror(errno)); 131131962Smp if(dag_close(p->fd) < 0) 132145479Smp fprintf(stderr,"dag_close %s: %s\n", p->md.device, strerror(errno)); 133145479Smp 134145479Smp free(p->md.device); 135145479Smp } 136145479Smp#else 137145479Smp if (p != NULL) { 13859243Sobrien if(dag_stop(p->fd) < 0) 13959243Sobrien fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 14059243Sobrien if(dag_close(p->fd) < 0) 14159243Sobrien fprintf(stderr,"dag_close: %s\n", strerror(errno)); 14259243Sobrien } 143131962Smp#endif 14459415Sobrien delete_pcap_dag(p); 14590446Smp /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ 14659243Sobrien} 147131962Smp 14859415Sobrienstatic void 14959415Sobrienatexit_handler(void) 15059243Sobrien{ 15159415Sobrien while (pcap_dags != NULL) { 15259415Sobrien if (pcap_dags->pid == getpid()) { 15359243Sobrien dag_platform_close(pcap_dags->p); 15459415Sobrien } else { 15559415Sobrien delete_pcap_dag(pcap_dags->p); 15659243Sobrien } 15759415Sobrien } 15859415Sobrien} 15959243Sobrien 16059243Sobrienstatic int 16159243Sobriennew_pcap_dag(pcap_t *p) 16259243Sobrien{ 16383098Smp pcap_dag_node_t *node = NULL; 16483098Smp 16590446Smp if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { 16690446Smp return -1; 167231990Smp } 168131962Smp 169131962Smp if (!atexit_handler_installed) { 170131962Smp atexit(atexit_handler); 171131962Smp atexit_handler_installed = 1; 172131962Smp } 173131962Smp 174131962Smp node->next = pcap_dags; 175131962Smp node->p = p; 176131962Smp node->pid = getpid(); 177131962Smp 178131962Smp pcap_dags = node; 179131962Smp 180131962Smp return 0; 181131962Smp} 182131962Smp 183195609Smp/* 18490446Smp * Read at most max_packets from the capture stream and call the callback 18569408Sache * for each of them. Returns the number of packets handled, -1 if an 18690446Smp * error occured, or -2 if we were told to break out of the loop. 18790446Smp */ 18890446Smpstatic int 18990446Smpdag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 19090446Smp{ 19190446Smp unsigned int processed = 0; 19290446Smp int flags = p->md.dag_offset_flags; 19369408Sache unsigned int nonblocking = flags & DAGF_NONBLOCK; 19469408Sache 19590446Smp for (;;) 19690446Smp { 19790446Smp /* Get the next bufferful of packets (if necessary). */ 19890446Smp while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) { 19959243Sobrien 20059415Sobrien /* 20159415Sobrien * Has "pcap_breakloop()" been called? 20290446Smp */ 20359415Sobrien if (p->break_loop) { 20459415Sobrien /* 20590446Smp * Yes - clear the flag that indicates that 20659243Sobrien * it has, and return -2 to indicate that 20759243Sobrien * we were told to break out of the loop. 20883098Smp */ 20959243Sobrien p->break_loop = 0; 21059415Sobrien return -2; 21159415Sobrien } 21290446Smp 21359415Sobrien p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), flags); 21459415Sobrien if (nonblocking && (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size)) 21590446Smp { 21659243Sobrien /* Pcap is configured to process only available packets, and there aren't any. */ 21759243Sobrien return 0; 21883098Smp } 21959243Sobrien } 22059415Sobrien 22159415Sobrien /* Process the packets. */ 22290446Smp while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) { 22359415Sobrien 22459415Sobrien unsigned short packet_len = 0; 22590446Smp int caplen = 0; 22659243Sobrien struct pcap_pkthdr pcap_header; 22759243Sobrien 22883098Smp dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom); 22959243Sobrien u_char *dp = ((u_char *)header) + dag_record_size; 23059415Sobrien unsigned short rlen; 23159415Sobrien 23290446Smp /* 23359415Sobrien * Has "pcap_breakloop()" been called? 23459415Sobrien */ 23590446Smp if (p->break_loop) { 23659243Sobrien /* 23759243Sobrien * Yes - clear the flag that indicates that 23883098Smp * it has, and return -2 to indicate that 23959243Sobrien * we were told to break out of the loop. 24059243Sobrien */ 24159243Sobrien p->break_loop = 0; 24259243Sobrien return -2; 24359243Sobrien } 24459243Sobrien 24559243Sobrien rlen = ntohs(header->rlen); 24659243Sobrien if (rlen < dag_record_size) 24759243Sobrien { 24859243Sobrien strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); 24959243Sobrien return -1; 25059243Sobrien } 25159243Sobrien p->md.dag_mem_bottom += rlen; 25259243Sobrien 25359243Sobrien switch(header->type) { 25459243Sobrien case TYPE_AAL5: 255231990Smp case TYPE_ATM: 25659243Sobrien if (header->type == TYPE_AAL5) { 25759243Sobrien packet_len = ntohs(header->wlen); 25859243Sobrien caplen = rlen - dag_record_size; 25959243Sobrien } else { 26059243Sobrien caplen = packet_len = ATM_CELL_SIZE; 26159243Sobrien } 26259243Sobrien if (p->linktype == DLT_SUNATM) { 26383098Smp struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; 26459243Sobrien unsigned long rawatm; 26559243Sobrien 26659243Sobrien rawatm = ntohl(*((unsigned long *)dp)); 26759243Sobrien sunatm->vci = htons((rawatm >> 4) & 0xffff); 26859243Sobrien sunatm->vpi = (rawatm >> 20) & 0x00ff; 26959243Sobrien sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | 27059243Sobrien ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : 27159243Sobrien ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : 27259243Sobrien ((dp[ATM_HDR_SIZE] == 0xaa && 27359243Sobrien dp[ATM_HDR_SIZE+1] == 0xaa && 27459243Sobrien dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); 27559243Sobrien 27659243Sobrien } else { 27759243Sobrien packet_len -= ATM_HDR_SIZE; 27859243Sobrien caplen -= ATM_HDR_SIZE; 27959243Sobrien dp += ATM_HDR_SIZE; 28059243Sobrien } 28159243Sobrien break; 28259243Sobrien 28359243Sobrien case TYPE_ETH: 28459243Sobrien packet_len = ntohs(header->wlen); 28559243Sobrien packet_len -= (p->md.dag_fcs_bits >> 3); 28659243Sobrien caplen = rlen - dag_record_size - 2; 28759243Sobrien if (caplen > packet_len) { 28859243Sobrien caplen = packet_len; 28959243Sobrien } 29059243Sobrien dp += 2; 29159243Sobrien break; 29259243Sobrien 29359243Sobrien case TYPE_HDLC_POS: 29459243Sobrien packet_len = ntohs(header->wlen); 29559243Sobrien packet_len -= (p->md.dag_fcs_bits >> 3); 29659243Sobrien caplen = rlen - dag_record_size; 29759243Sobrien if (caplen > packet_len) { 29859243Sobrien caplen = packet_len; 29959243Sobrien } 30059243Sobrien break; 30159243Sobrien } 30259243Sobrien 30359243Sobrien if (caplen > p->snapshot) 30459243Sobrien caplen = p->snapshot; 30559243Sobrien 30659243Sobrien /* Count lost packets. */ 30759243Sobrien if (header->lctr) { 30859243Sobrien if (p->md.stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { 30959243Sobrien p->md.stat.ps_drop = UINT_MAX; 310231990Smp } else { 311231990Smp p->md.stat.ps_drop += ntohs(header->lctr); 31259243Sobrien } 31359243Sobrien } 31459243Sobrien 31559243Sobrien /* Run the packet filter if there is one. */ 31659243Sobrien if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { 31759243Sobrien 31859243Sobrien /* convert between timestamp formats */ 31959243Sobrien register unsigned long long ts; 32059243Sobrien 32159243Sobrien if (IS_BIGENDIAN()) { 32259243Sobrien ts = SWAP_TS(header->ts); 32359243Sobrien } else { 32459243Sobrien ts = header->ts; 32559243Sobrien } 32659243Sobrien 32759243Sobrien pcap_header.ts.tv_sec = ts >> 32; 32859243Sobrien ts = (ts & 0xffffffffULL) * 1000000; 32959243Sobrien ts += 0x80000000; /* rounding */ 33059243Sobrien pcap_header.ts.tv_usec = ts >> 32; 33159243Sobrien if (pcap_header.ts.tv_usec >= 1000000) { 33259243Sobrien pcap_header.ts.tv_usec -= 1000000; 33359243Sobrien pcap_header.ts.tv_sec++; 33459243Sobrien } 33559243Sobrien 33659243Sobrien /* Fill in our own header data */ 33759243Sobrien pcap_header.caplen = caplen; 33859243Sobrien pcap_header.len = packet_len; 33959243Sobrien 34059243Sobrien /* Count the packet. */ 34159243Sobrien p->md.stat.ps_recv++; 34259243Sobrien 34359243Sobrien /* Call the user supplied callback function */ 344100616Smp callback(user, &pcap_header, dp); 345100616Smp 346100616Smp /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ 34759243Sobrien processed++; 34859243Sobrien if (processed == cnt) 34959243Sobrien { 35059243Sobrien /* Reached the user-specified limit. */ 35159243Sobrien return cnt; 35259243Sobrien } 35359243Sobrien } 35459243Sobrien } 35559243Sobrien 35659243Sobrien if (nonblocking || processed) 35759243Sobrien { 35859243Sobrien return processed; 359195609Smp } 360195609Smp } 36159243Sobrien 36259243Sobrien return processed; 36359243Sobrien} 36459243Sobrien 36559243Sobrienstatic int 36659243Sobriendag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 36759243Sobrien{ 36859243Sobrien strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", 36959243Sobrien PCAP_ERRBUF_SIZE); 37059243Sobrien return (-1); 37159243Sobrien} 37259243Sobrien 37359243Sobrien/* 37459243Sobrien * Get a handle for a live capture from the given DAG device. Passing a NULL 37559243Sobrien * device will result in a failure. The promisc flag is ignored because DAG 37659243Sobrien * cards are always promiscuous. The to_ms parameter is also ignored as it is 37759243Sobrien * not supported in hardware. 37859243Sobrien * 37959243Sobrien * See also pcap(3). 38059243Sobrien */ 38159243Sobrienpcap_t * 38259243Sobriendag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf) 38359243Sobrien{ 38459243Sobrien char conf[30]; /* dag configure string */ 385231990Smp pcap_t *handle; 38659243Sobrien char *s; 38759243Sobrien int n; 38859243Sobrien daginf_t* daginf; 389231990Smp 39059243Sobrien if (device == NULL) { 391131962Smp snprintf(ebuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); 39259243Sobrien return NULL; 39359243Sobrien } 39459243Sobrien /* Allocate a handle for this session. */ 39559243Sobrien 39659243Sobrien handle = malloc(sizeof(*handle)); 397231990Smp if (handle == NULL) { 39859243Sobrien snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc %s: %s", device, pcap_strerror(errno)); 39959243Sobrien return NULL; 40059243Sobrien } 40159243Sobrien 40259243Sobrien /* Initialize some components of the pcap structure. */ 40359243Sobrien 40459243Sobrien memset(handle, 0, sizeof(*handle)); 40559243Sobrien 406167465Smp if (strstr(device, "/dev") == NULL) { 40759243Sobrien char * newDev = (char *)malloc(strlen(device) + 6); 40859243Sobrien newDev[0] = '\0'; 40959243Sobrien strcat(newDev, "/dev/"); 41059243Sobrien strcat(newDev,device); 41159243Sobrien device = newDev; 41259243Sobrien } else { 41359243Sobrien device = strdup(device); 41459243Sobrien } 41559243Sobrien 41659243Sobrien if (device == NULL) { 41759243Sobrien snprintf(ebuf, PCAP_ERRBUF_SIZE, "str_dup: %s\n", pcap_strerror(errno)); 41859243Sobrien goto fail; 41959243Sobrien } 42059243Sobrien 42159243Sobrien /* setup device parameters */ 42259243Sobrien if((handle->fd = dag_open((char *)device)) < 0) { 42359243Sobrien snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno)); 42459243Sobrien goto fail; 42559243Sobrien } 42659243Sobrien 42759243Sobrien /* set the card snap length to the specified snaplen parameter */ 42859243Sobrien if (snaplen == 0 || snaplen > MAX_DAG_SNAPLEN) { 42959243Sobrien snaplen = MAX_DAG_SNAPLEN; 43059243Sobrien } else if (snaplen < MIN_DAG_SNAPLEN) { 431167465Smp snaplen = MIN_DAG_SNAPLEN; 43259243Sobrien } 43359243Sobrien /* snap len has to be a multiple of 4 */ 43459243Sobrien snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); 43583098Smp 43683098Smp if(dag_configure(handle->fd, conf) < 0) { 43759243Sobrien snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno)); 43859243Sobrien goto fail; 43959243Sobrien } 440131962Smp 44159243Sobrien if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { 44259243Sobrien snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno)); 44359243Sobrien goto fail; 44459243Sobrien } 44559243Sobrien 44659243Sobrien if(dag_start(handle->fd) < 0) { 44759243Sobrien snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno)); 44859243Sobrien goto fail; 44959243Sobrien } 45059243Sobrien 45159243Sobrien /* 45259243Sobrien * Important! You have to ensure bottom is properly 45359243Sobrien * initialized to zero on startup, it won't give you 45459243Sobrien * a compiler warning if you make this mistake! 45559243Sobrien */ 45659243Sobrien handle->md.dag_mem_bottom = 0; 45759243Sobrien handle->md.dag_mem_top = 0; 45859243Sobrien handle->md.dag_fcs_bits = 32; 45959243Sobrien 460167465Smp /* Query the card first for special cases. */ 461195609Smp daginf = dag_info(handle->fd); 462195609Smp if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) 463195609Smp { 464167465Smp /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ 465195609Smp handle->md.dag_fcs_bits = 0; 466195609Smp } 467167465Smp 46859243Sobrien /* Then allow an environment variable to override. */ 46959243Sobrien if ((s = getenv("ERF_FCS_BITS")) != NULL) { 47059243Sobrien if ((n = atoi(s)) == 0 || n == 16|| n == 32) { 47159243Sobrien handle->md.dag_fcs_bits = n; 47259243Sobrien } else { 47359243Sobrien snprintf(ebuf, PCAP_ERRBUF_SIZE, 47459243Sobrien "pcap_open_live %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n); 47559243Sobrien goto fail; 47659243Sobrien } 47759243Sobrien } 47859243Sobrien 47959243Sobrien handle->snapshot = snaplen; 48069408Sache /*handle->md.timeout = to_ms; */ 48159243Sobrien 48259243Sobrien handle->linktype = -1; 48359243Sobrien if (dag_get_datalink(handle) < 0) { 484145479Smp strcpy(ebuf, handle->errbuf); 48559243Sobrien goto fail; 48659243Sobrien } 48759243Sobrien 48883098Smp handle->bufsize = 0; 48983098Smp 49083098Smp if (new_pcap_dag(handle) < 0) { 49183098Smp snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno)); 49283098Smp goto fail; 49359243Sobrien } 49459243Sobrien 49559243Sobrien /* 49659243Sobrien * "select()" and "poll()" don't (yet) work on DAG device descriptors. 49759243Sobrien */ 49859243Sobrien handle->selectable_fd = -1; 49959243Sobrien 50059243Sobrien#ifdef linux 50159243Sobrien handle->md.device = (char *)device; 50269408Sache#else 50359243Sobrien free((char *)device); 50459243Sobrien device = NULL; 50559243Sobrien#endif 50659243Sobrien 50783098Smp handle->read_op = dag_read; 50883098Smp handle->inject_op = dag_inject; 50983098Smp handle->setfilter_op = dag_setfilter; 510100616Smp handle->setdirection_op = NULL; /* Not implemented.*/ 511145479Smp handle->set_datalink_op = dag_set_datalink; 512145479Smp handle->getnonblock_op = pcap_getnonblock_fd; 513195609Smp handle->setnonblock_op = dag_setnonblock; 514195609Smp handle->stats_op = dag_stats; 515231990Smp handle->close_op = dag_platform_close; 516231990Smp 517231990Smp return handle; 518231990Smp 519fail: 520 if (device != NULL) { 521 free((char *)device); 522 } 523 if (handle != NULL) { 524 /* 525 * Get rid of any link-layer type list we allocated. 526 */ 527 if (handle->dlt_list != NULL) { 528 free(handle->dlt_list); 529 } 530 free(handle); 531 } 532 533 return NULL; 534} 535 536static int 537dag_stats(pcap_t *p, struct pcap_stat *ps) { 538 /* This needs to be filled out correctly. Hopefully a dagapi call will 539 provide all necessary information. 540 */ 541 /*p->md.stat.ps_recv = 0;*/ 542 /*p->md.stat.ps_drop = 0;*/ 543 544 *ps = p->md.stat; 545 546 return 0; 547} 548 549/* 550 * Get from "/proc/dag" all interfaces listed there; if they're 551 * already in the list of interfaces we have, that won't add another 552 * instance, but if they're not, that'll add them. 553 * 554 * We don't bother getting any addresses for them. 555 * 556 * We also don't fail if we couldn't open "/proc/dag"; we just leave 557 * the list of interfaces as is. 558 */ 559int 560dag_platform_finddevs(pcap_if_t **devlistp, char *errbuf) 561{ 562 FILE *proc_dag_f; 563 char linebuf[512]; 564 int linenum; 565 unsigned char *p; 566 char name[512]; /* XXX - pick a size */ 567 char *q; 568 int ret = 0; 569 570 /* Quick exit if /proc/dag not readable */ 571 proc_dag_f = fopen("/proc/dag", "r"); 572 if (proc_dag_f == NULL) 573 { 574 int i; 575 char dev[16] = "dagx"; 576 577 for (i = '0'; ret == 0 && i <= '9'; i++) { 578 dev[3] = i; 579 if (pcap_add_if(devlistp, dev, 0, NULL, errbuf) == -1) { 580 /* 581 * Failure. 582 */ 583 ret = -1; 584 } 585 } 586 587 return (ret); 588 } 589 590 for (linenum = 1; fgets(linebuf, sizeof linebuf, proc_dag_f) != NULL; linenum++) { 591 592 /* 593 * Skip the first two lines - they're headers. 594 */ 595 if (linenum <= 2) 596 continue; 597 598 p = &linebuf[0]; 599 600 if (*p == '\0' || *p == '\n' || *p != 'D') 601 continue; /* not a Dag line */ 602 603 /* 604 * Get the interface name. 605 */ 606 q = &name[0]; 607 while (*p != '\0' && *p != ':') { 608 if (*p != ' ') 609 *q++ = tolower(*p++); 610 else 611 p++; 612 } 613 *q = '\0'; 614 615 /* 616 * Add an entry for this interface, with no addresses. 617 */ 618 p[strlen(p) - 1] = '\0'; /* get rid of \n */ 619 if (pcap_add_if(devlistp, name, 0, strdup(p + 2), errbuf) == -1) { 620 /* 621 * Failure. 622 */ 623 ret = -1; 624 break; 625 } 626 } 627 if (ret != -1) { 628 /* 629 * Well, we didn't fail for any other reason; did we 630 * fail due to an error reading the file? 631 */ 632 if (ferror(proc_dag_f)) { 633 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 634 "Error reading /proc/dag: %s", 635 pcap_strerror(errno)); 636 ret = -1; 637 } 638 } 639 640 (void)fclose(proc_dag_f); 641 return (ret); 642} 643 644/* 645 * Installs the given bpf filter program in the given pcap structure. There is 646 * no attempt to store the filter in kernel memory as that is not supported 647 * with DAG cards. 648 */ 649static int 650dag_setfilter(pcap_t *p, struct bpf_program *fp) 651{ 652 if (!p) 653 return -1; 654 if (!fp) { 655 strncpy(p->errbuf, "setfilter: No filter specified", 656 sizeof(p->errbuf)); 657 return -1; 658 } 659 660 /* Make our private copy of the filter */ 661 662 if (install_bpf_program(p, fp) < 0) 663 return -1; 664 665 p->md.use_bpf = 0; 666 667 return (0); 668} 669 670static int 671dag_set_datalink(pcap_t *p, int dlt) 672{ 673 p->linktype = dlt; 674 675 return (0); 676} 677 678static int 679dag_setnonblock(pcap_t *p, int nonblock, char *errbuf) 680{ 681 /* 682 * Set non-blocking mode on the FD. 683 * XXX - is that necessary? If not, don't bother calling it, 684 * and have a "dag_getnonblock()" function that looks at 685 * "p->md.dag_offset_flags". 686 */ 687 if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0) 688 return (-1); 689 690 if (nonblock) { 691 p->md.dag_offset_flags |= DAGF_NONBLOCK; 692 } else { 693 p->md.dag_offset_flags &= ~DAGF_NONBLOCK; 694 } 695 return (0); 696} 697 698static int 699dag_get_datalink(pcap_t *p) 700{ 701 int daglinktype; 702 703 if (p->dlt_list == NULL && (p->dlt_list = malloc(2*sizeof(*(p->dlt_list)))) == NULL) { 704 (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); 705 return (-1); 706 } 707 708 /* Check the type through a dagapi call. */ 709 daglinktype = dag_linktype(p->fd); 710 711 switch(daglinktype) { 712 713 case TYPE_HDLC_POS: 714 if (p->dlt_list != NULL) { 715 p->dlt_count = 2; 716 p->dlt_list[0] = DLT_CHDLC; 717 p->dlt_list[1] = DLT_PPP_SERIAL; 718 } 719 p->linktype = DLT_CHDLC; 720 break; 721 722 case TYPE_ETH: 723 /* 724 * This is (presumably) a real Ethernet capture; give it a 725 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 726 * that an application can let you choose it, in case you're 727 * capturing DOCSIS traffic that a Cisco Cable Modem 728 * Termination System is putting out onto an Ethernet (it 729 * doesn't put an Ethernet header onto the wire, it puts raw 730 * DOCSIS frames out on the wire inside the low-level 731 * Ethernet framing). 732 */ 733 if (p->dlt_list != NULL) { 734 p->dlt_count = 2; 735 p->dlt_list[0] = DLT_EN10MB; 736 p->dlt_list[1] = DLT_DOCSIS; 737 } 738 p->linktype = DLT_EN10MB; 739 break; 740 741 case TYPE_AAL5: 742 case TYPE_ATM: 743 if (p->dlt_list != NULL) { 744 p->dlt_count = 2; 745 p->dlt_list[0] = DLT_ATM_RFC1483; 746 p->dlt_list[1] = DLT_SUNATM; 747 } 748 p->linktype = DLT_ATM_RFC1483; 749 break; 750 751 752 case TYPE_LEGACY: 753 p->linktype = DLT_NULL; 754 break; 755 756 default: 757 snprintf(p->errbuf, sizeof(p->errbuf), "unknown DAG linktype %d\n", daglinktype); 758 return (-1); 759 760 } 761 762 return p->linktype; 763} 764