pcap-dag.c revision 146768
1127664Sbms/* 2127664Sbms * pcap-dag.c: Packet capture interface for Endace DAG card. 3127664Sbms * 4127664Sbms * The functionality of this code attempts to mimic that of pcap-linux as much 5127664Sbms * as possible. This code is compiled in several different ways depending on 6127664Sbms * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not 7127664Sbms * defined it should not get compiled in, otherwise if DAG_ONLY is defined then 8127664Sbms * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY 9127664Sbms * is not defined then nothing is altered - the dag_ functions will be 10127664Sbms * called as required from their pcap-linux/bpf equivalents. 11127664Sbms * 12146768Ssam * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) 13146768Ssam * Modifications: Jesper Peterson, Koryn Grant <support@endace.com> 14127664Sbms */ 15127664Sbms 16127664Sbms#ifndef lint 17127664Sbmsstatic const char rcsid[] _U_ = 18146768Ssam "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.21 2005/04/03 23:56:47 guy Exp $ (LBL)"; 19127664Sbms#endif 20127664Sbms 21127664Sbms#ifdef HAVE_CONFIG_H 22127664Sbms#include "config.h" 23127664Sbms#endif 24127664Sbms 25127664Sbms#include <sys/param.h> /* optionally get BSD define */ 26127664Sbms 27127664Sbms#include <stdlib.h> 28127664Sbms#include <string.h> 29127664Sbms#include <errno.h> 30127664Sbms 31127664Sbms#include "pcap-int.h" 32127664Sbms 33127664Sbms#include <ctype.h> 34127664Sbms#include <netinet/in.h> 35127664Sbms#include <sys/mman.h> 36127664Sbms#include <sys/socket.h> 37127664Sbms#include <sys/types.h> 38127664Sbms#include <unistd.h> 39127664Sbms 40127664Sbmsstruct mbuf; /* Squelch compiler warnings on some platforms for */ 41127664Sbmsstruct rtentry; /* declarations in <net/if.h> */ 42127664Sbms#include <net/if.h> 43127664Sbms 44146768Ssam#include "dagnew.h" 45146768Ssam#include "dagapi.h" 46127664Sbms 47127664Sbms#define MIN_DAG_SNAPLEN 12 48127664Sbms#define MAX_DAG_SNAPLEN 2040 49146768Ssam#define ATM_CELL_SIZE 52 50146768Ssam#define ATM_HDR_SIZE 4 51127664Sbms 52146768Ssam/* SunATM pseudo header */ 53146768Ssamstruct sunatm_hdr { 54146768Ssam unsigned char flags; /* destination and traffic type */ 55146768Ssam unsigned char vpi; /* VPI */ 56146768Ssam unsigned short vci; /* VCI */ 57146768Ssam}; 58146768Ssam 59127664Sbmstypedef struct pcap_dag_node { 60146768Ssam struct pcap_dag_node *next; 61146768Ssam pcap_t *p; 62146768Ssam pid_t pid; 63127664Sbms} pcap_dag_node_t; 64127664Sbms 65127664Sbmsstatic pcap_dag_node_t *pcap_dags = NULL; 66127664Sbmsstatic int atexit_handler_installed = 0; 67127664Sbmsstatic const unsigned short endian_test_word = 0x0100; 68127664Sbms 69127664Sbms#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) 70127664Sbms 71127664Sbms/* 72127664Sbms * Swap byte ordering of unsigned long long timestamp on a big endian 73127664Sbms * machine. 74127664Sbms */ 75127664Sbms#define SWAP_TS(ull) ((ull & 0xff00000000000000LL) >> 56) | \ 76127664Sbms ((ull & 0x00ff000000000000LL) >> 40) | \ 77127664Sbms ((ull & 0x0000ff0000000000LL) >> 24) | \ 78127664Sbms ((ull & 0x000000ff00000000LL) >> 8) | \ 79127664Sbms ((ull & 0x00000000ff000000LL) << 8) | \ 80127664Sbms ((ull & 0x0000000000ff0000LL) << 24) | \ 81127664Sbms ((ull & 0x000000000000ff00LL) << 40) | \ 82127664Sbms ((ull & 0x00000000000000ffLL) << 56) 83127664Sbms 84127664Sbms 85127664Sbms#ifdef DAG_ONLY 86127664Sbms/* This code is required when compiling for a DAG device only. */ 87127664Sbms#include "pcap-dag.h" 88127664Sbms 89127664Sbms/* Replace dag function names with pcap equivalent. */ 90127664Sbms#define dag_open_live pcap_open_live 91127664Sbms#define dag_platform_finddevs pcap_platform_finddevs 92127664Sbms#endif /* DAG_ONLY */ 93127664Sbms 94127664Sbmsstatic int dag_setfilter(pcap_t *p, struct bpf_program *fp); 95127664Sbmsstatic int dag_stats(pcap_t *p, struct pcap_stat *ps); 96127664Sbmsstatic int dag_set_datalink(pcap_t *p, int dlt); 97127664Sbmsstatic int dag_get_datalink(pcap_t *p); 98127664Sbmsstatic int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf); 99127664Sbms 100146768Ssamstatic void 101146768Ssamdelete_pcap_dag(pcap_t *p) 102146768Ssam{ 103146768Ssam pcap_dag_node_t *curr = NULL, *prev = NULL; 104127664Sbms 105146768Ssam for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { 106146768Ssam /* empty */ 107146768Ssam } 108127664Sbms 109146768Ssam if (curr != NULL && curr->p == p) { 110146768Ssam if (prev != NULL) { 111146768Ssam prev->next = curr->next; 112146768Ssam } else { 113146768Ssam pcap_dags = curr->next; 114146768Ssam } 115146768Ssam } 116127664Sbms} 117127664Sbms 118127664Sbms/* 119127664Sbms * Performs a graceful shutdown of the DAG card, frees dynamic memory held 120127664Sbms * in the pcap_t structure, and closes the file descriptor for the DAG card. 121127664Sbms */ 122127664Sbms 123146768Ssamstatic void 124146768Ssamdag_platform_close(pcap_t *p) 125146768Ssam{ 126127664Sbms 127127664Sbms#ifdef linux 128146768Ssam if (p != NULL && p->md.device != NULL) { 129146768Ssam if(dag_stop(p->fd) < 0) 130146768Ssam fprintf(stderr,"dag_stop %s: %s\n", p->md.device, strerror(errno)); 131146768Ssam if(dag_close(p->fd) < 0) 132146768Ssam fprintf(stderr,"dag_close %s: %s\n", p->md.device, strerror(errno)); 133146768Ssam 134146768Ssam free(p->md.device); 135146768Ssam } 136127664Sbms#else 137146768Ssam if (p != NULL) { 138146768Ssam if(dag_stop(p->fd) < 0) 139146768Ssam fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 140146768Ssam if(dag_close(p->fd) < 0) 141146768Ssam fprintf(stderr,"dag_close: %s\n", strerror(errno)); 142146768Ssam } 143127664Sbms#endif 144146768Ssam delete_pcap_dag(p); 145146768Ssam /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ 146127664Sbms} 147127664Sbms 148146768Ssamstatic void 149146768Ssamatexit_handler(void) 150146768Ssam{ 151146768Ssam while (pcap_dags != NULL) { 152146768Ssam if (pcap_dags->pid == getpid()) { 153146768Ssam dag_platform_close(pcap_dags->p); 154146768Ssam } else { 155146768Ssam delete_pcap_dag(pcap_dags->p); 156146768Ssam } 157146768Ssam } 158127664Sbms} 159127664Sbms 160146768Ssamstatic int 161146768Ssamnew_pcap_dag(pcap_t *p) 162146768Ssam{ 163146768Ssam pcap_dag_node_t *node = NULL; 164127664Sbms 165146768Ssam if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { 166146768Ssam return -1; 167146768Ssam } 168127664Sbms 169146768Ssam if (!atexit_handler_installed) { 170146768Ssam atexit(atexit_handler); 171146768Ssam atexit_handler_installed = 1; 172146768Ssam } 173127664Sbms 174146768Ssam node->next = pcap_dags; 175146768Ssam node->p = p; 176146768Ssam node->pid = getpid(); 177127664Sbms 178146768Ssam pcap_dags = node; 179127664Sbms 180146768Ssam return 0; 181127664Sbms} 182127664Sbms 183127664Sbms/* 184127664Sbms * Read at most max_packets from the capture stream and call the callback 185127664Sbms * for each of them. Returns the number of packets handled, -1 if an 186127664Sbms * error occured, or -2 if we were told to break out of the loop. 187127664Sbms */ 188146768Ssamstatic int 189146768Ssamdag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 190146768Ssam{ 191127664Sbms unsigned int processed = 0; 192127664Sbms int flags = p->md.dag_offset_flags; 193127664Sbms unsigned int nonblocking = flags & DAGF_NONBLOCK; 194127664Sbms 195127664Sbms for (;;) 196127664Sbms { 197127664Sbms /* Get the next bufferful of packets (if necessary). */ 198127664Sbms while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) { 199127664Sbms 200127664Sbms /* 201127664Sbms * Has "pcap_breakloop()" been called? 202127664Sbms */ 203127664Sbms if (p->break_loop) { 204127664Sbms /* 205127664Sbms * Yes - clear the flag that indicates that 206127664Sbms * it has, and return -2 to indicate that 207127664Sbms * we were told to break out of the loop. 208127664Sbms */ 209127664Sbms p->break_loop = 0; 210127664Sbms return -2; 211127664Sbms } 212127664Sbms 213127664Sbms p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), flags); 214146768Ssam if (nonblocking && (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size)) 215127664Sbms { 216127664Sbms /* Pcap is configured to process only available packets, and there aren't any. */ 217127664Sbms return 0; 218127664Sbms } 219127664Sbms } 220146768Ssam 221127664Sbms /* Process the packets. */ 222127664Sbms while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) { 223127664Sbms 224127664Sbms unsigned short packet_len = 0; 225127664Sbms int caplen = 0; 226127664Sbms struct pcap_pkthdr pcap_header; 227127664Sbms 228127664Sbms dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom); 229127664Sbms u_char *dp = ((u_char *)header) + dag_record_size; 230127664Sbms unsigned short rlen; 231127664Sbms 232127664Sbms /* 233127664Sbms * Has "pcap_breakloop()" been called? 234127664Sbms */ 235127664Sbms if (p->break_loop) { 236127664Sbms /* 237127664Sbms * Yes - clear the flag that indicates that 238127664Sbms * it has, and return -2 to indicate that 239127664Sbms * we were told to break out of the loop. 240127664Sbms */ 241127664Sbms p->break_loop = 0; 242127664Sbms return -2; 243127664Sbms } 244127664Sbms 245146768Ssam rlen = ntohs(header->rlen); 246146768Ssam if (rlen < dag_record_size) 247127664Sbms { 248146768Ssam strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); 249146768Ssam return -1; 250127664Sbms } 251127664Sbms p->md.dag_mem_bottom += rlen; 252127664Sbms 253127664Sbms switch(header->type) { 254146768Ssam case TYPE_AAL5: 255127664Sbms case TYPE_ATM: 256146768Ssam if (header->type == TYPE_AAL5) { 257146768Ssam packet_len = ntohs(header->wlen); 258146768Ssam caplen = rlen - dag_record_size; 259146768Ssam } else { 260146768Ssam caplen = packet_len = ATM_CELL_SIZE; 261146768Ssam } 262146768Ssam if (p->linktype == DLT_SUNATM) { 263146768Ssam struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; 264146768Ssam unsigned long rawatm; 265146768Ssam 266146768Ssam rawatm = ntohl(*((unsigned long *)dp)); 267146768Ssam sunatm->vci = htons((rawatm >> 4) & 0xffff); 268146768Ssam sunatm->vpi = (rawatm >> 20) & 0x00ff; 269146768Ssam sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | 270146768Ssam ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : 271146768Ssam ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : 272146768Ssam ((dp[ATM_HDR_SIZE] == 0xaa && 273146768Ssam dp[ATM_HDR_SIZE+1] == 0xaa && 274146768Ssam dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); 275146768Ssam 276146768Ssam } else { 277146768Ssam packet_len -= ATM_HDR_SIZE; 278146768Ssam caplen -= ATM_HDR_SIZE; 279146768Ssam dp += ATM_HDR_SIZE; 280146768Ssam } 281127664Sbms break; 282127664Sbms 283127664Sbms case TYPE_ETH: 284127664Sbms packet_len = ntohs(header->wlen); 285127664Sbms packet_len -= (p->md.dag_fcs_bits >> 3); 286127664Sbms caplen = rlen - dag_record_size - 2; 287146768Ssam if (caplen > packet_len) { 288127664Sbms caplen = packet_len; 289127664Sbms } 290127664Sbms dp += 2; 291127664Sbms break; 292127664Sbms 293127664Sbms case TYPE_HDLC_POS: 294127664Sbms packet_len = ntohs(header->wlen); 295127664Sbms packet_len -= (p->md.dag_fcs_bits >> 3); 296127664Sbms caplen = rlen - dag_record_size; 297146768Ssam if (caplen > packet_len) { 298127664Sbms caplen = packet_len; 299127664Sbms } 300127664Sbms break; 301127664Sbms } 302127664Sbms 303127664Sbms if (caplen > p->snapshot) 304127664Sbms caplen = p->snapshot; 305127664Sbms 306127664Sbms /* Count lost packets. */ 307127664Sbms if (header->lctr) { 308146768Ssam if (p->md.stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { 309127664Sbms p->md.stat.ps_drop = UINT_MAX; 310127664Sbms } else { 311146768Ssam p->md.stat.ps_drop += ntohs(header->lctr); 312127664Sbms } 313127664Sbms } 314127664Sbms 315127664Sbms /* Run the packet filter if there is one. */ 316127664Sbms if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { 317127664Sbms 318127664Sbms /* convert between timestamp formats */ 319127664Sbms register unsigned long long ts; 320127664Sbms 321146768Ssam if (IS_BIGENDIAN()) { 322127664Sbms ts = SWAP_TS(header->ts); 323146768Ssam } else { 324127664Sbms ts = header->ts; 325127664Sbms } 326127664Sbms 327146768Ssam pcap_header.ts.tv_sec = ts >> 32; 328127664Sbms ts = (ts & 0xffffffffULL) * 1000000; 329127664Sbms ts += 0x80000000; /* rounding */ 330127664Sbms pcap_header.ts.tv_usec = ts >> 32; 331127664Sbms if (pcap_header.ts.tv_usec >= 1000000) { 332127664Sbms pcap_header.ts.tv_usec -= 1000000; 333127664Sbms pcap_header.ts.tv_sec++; 334127664Sbms } 335127664Sbms 336127664Sbms /* Fill in our own header data */ 337127664Sbms pcap_header.caplen = caplen; 338127664Sbms pcap_header.len = packet_len; 339146768Ssam 340127664Sbms /* Count the packet. */ 341127664Sbms p->md.stat.ps_recv++; 342146768Ssam 343127664Sbms /* Call the user supplied callback function */ 344127664Sbms callback(user, &pcap_header, dp); 345146768Ssam 346127664Sbms /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ 347127664Sbms processed++; 348127664Sbms if (processed == cnt) 349127664Sbms { 350127664Sbms /* Reached the user-specified limit. */ 351127664Sbms return cnt; 352127664Sbms } 353127664Sbms } 354127664Sbms } 355127664Sbms 356127664Sbms if (nonblocking || processed) 357127664Sbms { 358127664Sbms return processed; 359127664Sbms } 360127664Sbms } 361146768Ssam 362127664Sbms return processed; 363127664Sbms} 364127664Sbms 365146768Ssamstatic int 366146768Ssamdag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 367146768Ssam{ 368146768Ssam strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", 369146768Ssam PCAP_ERRBUF_SIZE); 370146768Ssam return (-1); 371146768Ssam} 372146768Ssam 373127664Sbms/* 374127664Sbms * Get a handle for a live capture from the given DAG device. Passing a NULL 375127664Sbms * device will result in a failure. The promisc flag is ignored because DAG 376127664Sbms * cards are always promiscuous. The to_ms parameter is also ignored as it is 377127664Sbms * not supported in hardware. 378127664Sbms * 379127664Sbms * See also pcap(3). 380127664Sbms */ 381146768Ssampcap_t * 382146768Ssamdag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf) 383146768Ssam{ 384146768Ssam char conf[30]; /* dag configure string */ 385146768Ssam pcap_t *handle; 386146768Ssam char *s; 387146768Ssam int n; 388146768Ssam daginf_t* daginf; 389146768Ssam 390146768Ssam if (device == NULL) { 391146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); 392146768Ssam return NULL; 393146768Ssam } 394146768Ssam /* Allocate a handle for this session. */ 395127664Sbms 396146768Ssam handle = malloc(sizeof(*handle)); 397146768Ssam if (handle == NULL) { 398146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc %s: %s", device, pcap_strerror(errno)); 399146768Ssam return NULL; 400146768Ssam } 401146768Ssam 402146768Ssam /* Initialize some components of the pcap structure. */ 403146768Ssam 404146768Ssam memset(handle, 0, sizeof(*handle)); 405127664Sbms 406146768Ssam if (strstr(device, "/dev") == NULL) { 407146768Ssam char * newDev = (char *)malloc(strlen(device) + 6); 408146768Ssam newDev[0] = '\0'; 409146768Ssam strcat(newDev, "/dev/"); 410146768Ssam strcat(newDev,device); 411146768Ssam device = newDev; 412146768Ssam } else { 413146768Ssam device = strdup(device); 414146768Ssam } 415127664Sbms 416146768Ssam if (device == NULL) { 417146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "str_dup: %s\n", pcap_strerror(errno)); 418146768Ssam goto fail; 419146768Ssam } 420127664Sbms 421146768Ssam /* setup device parameters */ 422146768Ssam if((handle->fd = dag_open((char *)device)) < 0) { 423146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno)); 424146768Ssam goto fail; 425146768Ssam } 426127664Sbms 427146768Ssam /* set the card snap length to the specified snaplen parameter */ 428146768Ssam if (snaplen == 0 || snaplen > MAX_DAG_SNAPLEN) { 429146768Ssam snaplen = MAX_DAG_SNAPLEN; 430146768Ssam } else if (snaplen < MIN_DAG_SNAPLEN) { 431146768Ssam snaplen = MIN_DAG_SNAPLEN; 432146768Ssam } 433146768Ssam /* snap len has to be a multiple of 4 */ 434146768Ssam snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); 435127664Sbms 436146768Ssam if(dag_configure(handle->fd, conf) < 0) { 437146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno)); 438146768Ssam goto fail; 439146768Ssam } 440146768Ssam 441146768Ssam if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { 442146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno)); 443146768Ssam goto fail; 444146768Ssam } 445146768Ssam 446146768Ssam if(dag_start(handle->fd) < 0) { 447146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno)); 448146768Ssam goto fail; 449146768Ssam } 450127664Sbms 451146768Ssam /* 452146768Ssam * Important! You have to ensure bottom is properly 453146768Ssam * initialized to zero on startup, it won't give you 454146768Ssam * a compiler warning if you make this mistake! 455146768Ssam */ 456146768Ssam handle->md.dag_mem_bottom = 0; 457146768Ssam handle->md.dag_mem_top = 0; 458146768Ssam handle->md.dag_fcs_bits = 32; 459127664Sbms 460146768Ssam /* Query the card first for special cases. */ 461146768Ssam daginf = dag_info(handle->fd); 462146768Ssam if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) 463146768Ssam { 464146768Ssam /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ 465146768Ssam handle->md.dag_fcs_bits = 0; 466146768Ssam } 467127664Sbms 468146768Ssam /* Then allow an environment variable to override. */ 469146768Ssam if ((s = getenv("ERF_FCS_BITS")) != NULL) { 470146768Ssam if ((n = atoi(s)) == 0 || n == 16|| n == 32) { 471146768Ssam handle->md.dag_fcs_bits = n; 472146768Ssam } else { 473146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, 474146768Ssam "pcap_open_live %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n); 475146768Ssam goto fail; 476146768Ssam } 477146768Ssam } 478127664Sbms 479146768Ssam handle->snapshot = snaplen; 480146768Ssam /*handle->md.timeout = to_ms; */ 481127664Sbms 482146768Ssam handle->linktype = -1; 483146768Ssam if (dag_get_datalink(handle) < 0) { 484146768Ssam strcpy(ebuf, handle->errbuf); 485146768Ssam goto fail; 486146768Ssam } 487146768Ssam 488146768Ssam handle->bufsize = 0; 489127664Sbms 490146768Ssam if (new_pcap_dag(handle) < 0) { 491146768Ssam snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno)); 492146768Ssam goto fail; 493146768Ssam } 494127664Sbms 495146768Ssam /* 496146768Ssam * "select()" and "poll()" don't (yet) work on DAG device descriptors. 497146768Ssam */ 498146768Ssam handle->selectable_fd = -1; 499146768Ssam 500127664Sbms#ifdef linux 501146768Ssam handle->md.device = (char *)device; 502127664Sbms#else 503146768Ssam free((char *)device); 504146768Ssam device = NULL; 505127664Sbms#endif 506127664Sbms 507146768Ssam handle->read_op = dag_read; 508146768Ssam handle->inject_op = dag_inject; 509146768Ssam handle->setfilter_op = dag_setfilter; 510146768Ssam handle->set_datalink_op = dag_set_datalink; 511146768Ssam handle->getnonblock_op = pcap_getnonblock_fd; 512146768Ssam handle->setnonblock_op = dag_setnonblock; 513146768Ssam handle->stats_op = dag_stats; 514146768Ssam handle->close_op = dag_platform_close; 515127664Sbms 516146768Ssam return handle; 517127664Sbms 518127664Sbmsfail: 519146768Ssam if (device != NULL) { 520146768Ssam free((char *)device); 521146768Ssam } 522146768Ssam if (handle != NULL) { 523146768Ssam /* 524146768Ssam * Get rid of any link-layer type list we allocated. 525146768Ssam */ 526146768Ssam if (handle->dlt_list != NULL) { 527146768Ssam free(handle->dlt_list); 528146768Ssam } 529146768Ssam free(handle); 530146768Ssam } 531127664Sbms 532146768Ssam return NULL; 533127664Sbms} 534127664Sbms 535146768Ssamstatic int 536146768Ssamdag_stats(pcap_t *p, struct pcap_stat *ps) { 537146768Ssam /* This needs to be filled out correctly. Hopefully a dagapi call will 538146768Ssam provide all necessary information. 539146768Ssam */ 540146768Ssam /*p->md.stat.ps_recv = 0;*/ 541146768Ssam /*p->md.stat.ps_drop = 0;*/ 542146768Ssam 543146768Ssam *ps = p->md.stat; 544127664Sbms 545146768Ssam return 0; 546127664Sbms} 547127664Sbms 548127664Sbms/* 549127664Sbms * Get from "/proc/dag" all interfaces listed there; if they're 550127664Sbms * already in the list of interfaces we have, that won't add another 551127664Sbms * instance, but if they're not, that'll add them. 552127664Sbms * 553127664Sbms * We don't bother getting any addresses for them. 554127664Sbms * 555127664Sbms * We also don't fail if we couldn't open "/proc/dag"; we just leave 556127664Sbms * the list of interfaces as is. 557127664Sbms */ 558127664Sbmsint 559127664Sbmsdag_platform_finddevs(pcap_if_t **devlistp, char *errbuf) 560127664Sbms{ 561146768Ssam FILE *proc_dag_f; 562146768Ssam char linebuf[512]; 563146768Ssam int linenum; 564146768Ssam unsigned char *p; 565146768Ssam char name[512]; /* XXX - pick a size */ 566146768Ssam char *q; 567146768Ssam int ret = 0; 568127664Sbms 569146768Ssam /* Quick exit if /proc/dag not readable */ 570146768Ssam proc_dag_f = fopen("/proc/dag", "r"); 571146768Ssam if (proc_dag_f == NULL) 572146768Ssam { 573146768Ssam int i; 574146768Ssam char dev[16] = "dagx"; 575127664Sbms 576146768Ssam for (i = '0'; ret == 0 && i <= '9'; i++) { 577146768Ssam dev[3] = i; 578146768Ssam if (pcap_add_if(devlistp, dev, 0, NULL, errbuf) == -1) { 579146768Ssam /* 580146768Ssam * Failure. 581146768Ssam */ 582146768Ssam ret = -1; 583146768Ssam } 584146768Ssam } 585127664Sbms 586146768Ssam return (ret); 587146768Ssam } 588127664Sbms 589146768Ssam for (linenum = 1; fgets(linebuf, sizeof linebuf, proc_dag_f) != NULL; linenum++) { 590146768Ssam 591146768Ssam /* 592146768Ssam * Skip the first two lines - they're headers. 593146768Ssam */ 594146768Ssam if (linenum <= 2) 595146768Ssam continue; 596127664Sbms 597146768Ssam p = &linebuf[0]; 598127664Sbms 599146768Ssam if (*p == '\0' || *p == '\n' || *p != 'D') 600146768Ssam continue; /* not a Dag line */ 601127664Sbms 602146768Ssam /* 603146768Ssam * Get the interface name. 604146768Ssam */ 605146768Ssam q = &name[0]; 606146768Ssam while (*p != '\0' && *p != ':') { 607146768Ssam if (*p != ' ') 608146768Ssam *q++ = tolower(*p++); 609146768Ssam else 610146768Ssam p++; 611146768Ssam } 612146768Ssam *q = '\0'; 613127664Sbms 614146768Ssam /* 615146768Ssam * Add an entry for this interface, with no addresses. 616146768Ssam */ 617146768Ssam p[strlen(p) - 1] = '\0'; /* get rid of \n */ 618146768Ssam if (pcap_add_if(devlistp, name, 0, strdup(p + 2), errbuf) == -1) { 619146768Ssam /* 620146768Ssam * Failure. 621146768Ssam */ 622146768Ssam ret = -1; 623146768Ssam break; 624146768Ssam } 625146768Ssam } 626146768Ssam if (ret != -1) { 627146768Ssam /* 628146768Ssam * Well, we didn't fail for any other reason; did we 629146768Ssam * fail due to an error reading the file? 630146768Ssam */ 631146768Ssam if (ferror(proc_dag_f)) { 632146768Ssam (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, 633146768Ssam "Error reading /proc/dag: %s", 634146768Ssam pcap_strerror(errno)); 635146768Ssam ret = -1; 636146768Ssam } 637146768Ssam } 638146768Ssam 639146768Ssam (void)fclose(proc_dag_f); 640146768Ssam return (ret); 641127664Sbms} 642127664Sbms 643127664Sbms/* 644127664Sbms * Installs the given bpf filter program in the given pcap structure. There is 645127664Sbms * no attempt to store the filter in kernel memory as that is not supported 646127664Sbms * with DAG cards. 647127664Sbms */ 648146768Ssamstatic int 649146768Ssamdag_setfilter(pcap_t *p, struct bpf_program *fp) 650146768Ssam{ 651146768Ssam if (!p) 652146768Ssam return -1; 653146768Ssam if (!fp) { 654146768Ssam strncpy(p->errbuf, "setfilter: No filter specified", 655146768Ssam sizeof(p->errbuf)); 656146768Ssam return -1; 657146768Ssam } 658127664Sbms 659146768Ssam /* Make our private copy of the filter */ 660127664Sbms 661146768Ssam if (install_bpf_program(p, fp) < 0) 662146768Ssam return -1; 663127664Sbms 664146768Ssam p->md.use_bpf = 0; 665127664Sbms 666146768Ssam return (0); 667127664Sbms} 668127664Sbms 669127664Sbmsstatic int 670127664Sbmsdag_set_datalink(pcap_t *p, int dlt) 671127664Sbms{ 672146768Ssam p->linktype = dlt; 673146768Ssam 674127664Sbms return (0); 675127664Sbms} 676127664Sbms 677127664Sbmsstatic int 678127664Sbmsdag_setnonblock(pcap_t *p, int nonblock, char *errbuf) 679127664Sbms{ 680127664Sbms /* 681127664Sbms * Set non-blocking mode on the FD. 682127664Sbms * XXX - is that necessary? If not, don't bother calling it, 683127664Sbms * and have a "dag_getnonblock()" function that looks at 684127664Sbms * "p->md.dag_offset_flags". 685127664Sbms */ 686127664Sbms if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0) 687127664Sbms return (-1); 688127664Sbms 689127664Sbms if (nonblock) { 690127664Sbms p->md.dag_offset_flags |= DAGF_NONBLOCK; 691127664Sbms } else { 692127664Sbms p->md.dag_offset_flags &= ~DAGF_NONBLOCK; 693127664Sbms } 694127664Sbms return (0); 695127664Sbms} 696127664Sbms 697127664Sbmsstatic int 698127664Sbmsdag_get_datalink(pcap_t *p) 699127664Sbms{ 700146768Ssam int daglinktype; 701127664Sbms 702146768Ssam if (p->dlt_list == NULL && (p->dlt_list = malloc(2*sizeof(*(p->dlt_list)))) == NULL) { 703146768Ssam (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); 704146768Ssam return (-1); 705146768Ssam } 706127664Sbms 707146768Ssam /* Check the type through a dagapi call. */ 708146768Ssam daglinktype = dag_linktype(p->fd); 709127664Sbms 710146768Ssam switch(daglinktype) { 711127664Sbms 712146768Ssam case TYPE_HDLC_POS: 713146768Ssam if (p->dlt_list != NULL) { 714146768Ssam p->dlt_count = 2; 715146768Ssam p->dlt_list[0] = DLT_CHDLC; 716146768Ssam p->dlt_list[1] = DLT_PPP_SERIAL; 717146768Ssam } 718146768Ssam p->linktype = DLT_CHDLC; 719146768Ssam break; 720146768Ssam 721146768Ssam case TYPE_ETH: 722146768Ssam /* 723146768Ssam * This is (presumably) a real Ethernet capture; give it a 724146768Ssam * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 725146768Ssam * that an application can let you choose it, in case you're 726146768Ssam * capturing DOCSIS traffic that a Cisco Cable Modem 727146768Ssam * Termination System is putting out onto an Ethernet (it 728146768Ssam * doesn't put an Ethernet header onto the wire, it puts raw 729146768Ssam * DOCSIS frames out on the wire inside the low-level 730146768Ssam * Ethernet framing). 731146768Ssam */ 732146768Ssam if (p->dlt_list != NULL) { 733146768Ssam p->dlt_count = 2; 734146768Ssam p->dlt_list[0] = DLT_EN10MB; 735146768Ssam p->dlt_list[1] = DLT_DOCSIS; 736146768Ssam } 737146768Ssam p->linktype = DLT_EN10MB; 738146768Ssam break; 739146768Ssam 740146768Ssam case TYPE_AAL5: 741146768Ssam case TYPE_ATM: 742146768Ssam if (p->dlt_list != NULL) { 743146768Ssam p->dlt_count = 2; 744146768Ssam p->dlt_list[0] = DLT_ATM_RFC1483; 745146768Ssam p->dlt_list[1] = DLT_SUNATM; 746146768Ssam } 747146768Ssam p->linktype = DLT_ATM_RFC1483; 748146768Ssam break; 749146768Ssam 750146768Ssam 751146768Ssam case TYPE_LEGACY: 752146768Ssam p->linktype = DLT_NULL; 753146768Ssam break; 754146768Ssam 755146768Ssam default: 756146768Ssam snprintf(p->errbuf, sizeof(p->errbuf), "unknown DAG linktype %d\n", daglinktype); 757146768Ssam return (-1); 758146768Ssam 759146768Ssam } 760146768Ssam 761146768Ssam return p->linktype; 762127664Sbms} 763