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) 13162012Ssam * Modifications: Jesper Peterson <support@endace.com> 14162012Ssam * Koryn Grant <support@endace.com> 15162012Ssam * Stephen Donnelly <support@endace.com> 16127664Sbms */ 17127664Sbms 18127664Sbms#ifdef HAVE_CONFIG_H 19127664Sbms#include "config.h" 20127664Sbms#endif 21127664Sbms 22127664Sbms#include <sys/param.h> /* optionally get BSD define */ 23127664Sbms 24127664Sbms#include <stdlib.h> 25127664Sbms#include <string.h> 26127664Sbms#include <errno.h> 27127664Sbms 28127664Sbms#include "pcap-int.h" 29127664Sbms 30127664Sbms#include <ctype.h> 31127664Sbms#include <netinet/in.h> 32127664Sbms#include <sys/mman.h> 33127664Sbms#include <sys/socket.h> 34127664Sbms#include <sys/types.h> 35127664Sbms#include <unistd.h> 36127664Sbms 37127664Sbmsstruct mbuf; /* Squelch compiler warnings on some platforms for */ 38127664Sbmsstruct rtentry; /* declarations in <net/if.h> */ 39127664Sbms#include <net/if.h> 40127664Sbms 41146768Ssam#include "dagnew.h" 42146768Ssam#include "dagapi.h" 43127664Sbms 44190225Srpaulo#include "pcap-dag.h" 45190225Srpaulo 46251129Sdelphij/* 47251129Sdelphij * DAG devices have names beginning with "dag", followed by a number 48276768Sdelphij * from 0 to DAG_MAX_BOARDS, then optionally a colon and a stream number 49276768Sdelphij * from 0 to DAG_STREAM_MAX. 50251129Sdelphij */ 51276768Sdelphij#ifndef DAG_MAX_BOARDS 52276768Sdelphij#define DAG_MAX_BOARDS 32 53276768Sdelphij#endif 54251129Sdelphij 55146768Ssam#define ATM_CELL_SIZE 52 56146768Ssam#define ATM_HDR_SIZE 4 57127664Sbms 58172677Smlaier/* 59172677Smlaier * A header containing additional MTP information. 60172677Smlaier */ 61172677Smlaier#define MTP2_SENT_OFFSET 0 /* 1 byte */ 62172677Smlaier#define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */ 63172677Smlaier#define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */ 64172677Smlaier#define MTP2_HDR_LEN 4 /* length of the header */ 65172677Smlaier 66172677Smlaier#define MTP2_ANNEX_A_NOT_USED 0 67172677Smlaier#define MTP2_ANNEX_A_USED 1 68172677Smlaier#define MTP2_ANNEX_A_USED_UNKNOWN 2 69172677Smlaier 70146768Ssam/* SunATM pseudo header */ 71146768Ssamstruct sunatm_hdr { 72146768Ssam unsigned char flags; /* destination and traffic type */ 73146768Ssam unsigned char vpi; /* VPI */ 74146768Ssam unsigned short vci; /* VCI */ 75146768Ssam}; 76146768Ssam 77276768Sdelphij/* 78276768Sdelphij * Private data for capturing on DAG devices. 79276768Sdelphij */ 80276768Sdelphijstruct pcap_dag { 81276768Sdelphij struct pcap_stat stat; 82276768Sdelphij#ifdef HAVE_DAG_STREAMS_API 83276768Sdelphij u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */ 84276768Sdelphij u_char *dag_mem_top; /* DAG card current memory top pointer */ 85276768Sdelphij#else /* HAVE_DAG_STREAMS_API */ 86276768Sdelphij void *dag_mem_base; /* DAG card memory base address */ 87276768Sdelphij u_int dag_mem_bottom; /* DAG card current memory bottom offset */ 88276768Sdelphij u_int dag_mem_top; /* DAG card current memory top offset */ 89276768Sdelphij#endif /* HAVE_DAG_STREAMS_API */ 90276768Sdelphij int dag_fcs_bits; /* Number of checksum bits from link layer */ 91276768Sdelphij int dag_offset_flags; /* Flags to pass to dag_offset(). */ 92276768Sdelphij int dag_stream; /* DAG stream number */ 93276768Sdelphij int dag_timeout; /* timeout specified to pcap_open_live. 94276768Sdelphij * Same as in linux above, introduce 95276768Sdelphij * generally? */ 96276768Sdelphij}; 97276768Sdelphij 98127664Sbmstypedef struct pcap_dag_node { 99146768Ssam struct pcap_dag_node *next; 100146768Ssam pcap_t *p; 101146768Ssam pid_t pid; 102127664Sbms} pcap_dag_node_t; 103127664Sbms 104127664Sbmsstatic pcap_dag_node_t *pcap_dags = NULL; 105127664Sbmsstatic int atexit_handler_installed = 0; 106127664Sbmsstatic const unsigned short endian_test_word = 0x0100; 107127664Sbms 108127664Sbms#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) 109127664Sbms 110172677Smlaier#define MAX_DAG_PACKET 65536 111172677Smlaier 112172677Smlaierstatic unsigned char TempPkt[MAX_DAG_PACKET]; 113172677Smlaier 114127664Sbmsstatic int dag_setfilter(pcap_t *p, struct bpf_program *fp); 115127664Sbmsstatic int dag_stats(pcap_t *p, struct pcap_stat *ps); 116127664Sbmsstatic int dag_set_datalink(pcap_t *p, int dlt); 117127664Sbmsstatic int dag_get_datalink(pcap_t *p); 118127664Sbmsstatic int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf); 119127664Sbms 120146768Ssamstatic void 121146768Ssamdelete_pcap_dag(pcap_t *p) 122146768Ssam{ 123146768Ssam pcap_dag_node_t *curr = NULL, *prev = NULL; 124127664Sbms 125146768Ssam for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { 126146768Ssam /* empty */ 127146768Ssam } 128127664Sbms 129146768Ssam if (curr != NULL && curr->p == p) { 130146768Ssam if (prev != NULL) { 131146768Ssam prev->next = curr->next; 132146768Ssam } else { 133146768Ssam pcap_dags = curr->next; 134146768Ssam } 135146768Ssam } 136127664Sbms} 137127664Sbms 138127664Sbms/* 139127664Sbms * Performs a graceful shutdown of the DAG card, frees dynamic memory held 140127664Sbms * in the pcap_t structure, and closes the file descriptor for the DAG card. 141127664Sbms */ 142127664Sbms 143146768Ssamstatic void 144190225Srpaulodag_platform_cleanup(pcap_t *p) 145146768Ssam{ 146276768Sdelphij struct pcap_dag *pd; 147276768Sdelphij 148162012Ssam if (p != NULL) { 149276768Sdelphij pd = p->priv; 150162012Ssam#ifdef HAVE_DAG_STREAMS_API 151276768Sdelphij if(dag_stop_stream(p->fd, pd->dag_stream) < 0) 152162012Ssam fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); 153146768Ssam 154276768Sdelphij if(dag_detach_stream(p->fd, pd->dag_stream) < 0) 155162012Ssam fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); 156127664Sbms#else 157146768Ssam if(dag_stop(p->fd) < 0) 158146768Ssam fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 159162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 160190225Srpaulo if(p->fd != -1) { 161190225Srpaulo if(dag_close(p->fd) < 0) 162190225Srpaulo fprintf(stderr,"dag_close: %s\n", strerror(errno)); 163190225Srpaulo p->fd = -1; 164190225Srpaulo } 165190225Srpaulo delete_pcap_dag(p); 166190225Srpaulo pcap_cleanup_live_common(p); 167146768Ssam } 168146768Ssam /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ 169127664Sbms} 170127664Sbms 171146768Ssamstatic void 172146768Ssamatexit_handler(void) 173146768Ssam{ 174146768Ssam while (pcap_dags != NULL) { 175146768Ssam if (pcap_dags->pid == getpid()) { 176190225Srpaulo dag_platform_cleanup(pcap_dags->p); 177146768Ssam } else { 178146768Ssam delete_pcap_dag(pcap_dags->p); 179146768Ssam } 180146768Ssam } 181127664Sbms} 182127664Sbms 183146768Ssamstatic int 184146768Ssamnew_pcap_dag(pcap_t *p) 185146768Ssam{ 186146768Ssam pcap_dag_node_t *node = NULL; 187127664Sbms 188146768Ssam if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { 189146768Ssam return -1; 190146768Ssam } 191127664Sbms 192146768Ssam if (!atexit_handler_installed) { 193146768Ssam atexit(atexit_handler); 194146768Ssam atexit_handler_installed = 1; 195146768Ssam } 196127664Sbms 197146768Ssam node->next = pcap_dags; 198146768Ssam node->p = p; 199146768Ssam node->pid = getpid(); 200127664Sbms 201146768Ssam pcap_dags = node; 202127664Sbms 203146768Ssam return 0; 204127664Sbms} 205127664Sbms 206190225Srpaulostatic unsigned int 207190225Srpaulodag_erf_ext_header_count(uint8_t * erf, size_t len) 208190225Srpaulo{ 209190225Srpaulo uint32_t hdr_num = 0; 210190225Srpaulo uint8_t hdr_type; 211190225Srpaulo 212190225Srpaulo /* basic sanity checks */ 213190225Srpaulo if ( erf == NULL ) 214190225Srpaulo return 0; 215190225Srpaulo if ( len < 16 ) 216190225Srpaulo return 0; 217190225Srpaulo 218190225Srpaulo /* check if we have any extension headers */ 219190225Srpaulo if ( (erf[8] & 0x80) == 0x00 ) 220190225Srpaulo return 0; 221190225Srpaulo 222190225Srpaulo /* loop over the extension headers */ 223190225Srpaulo do { 224190225Srpaulo 225190225Srpaulo /* sanity check we have enough bytes */ 226276768Sdelphij if ( len < (24 + (hdr_num * 8)) ) 227190225Srpaulo return hdr_num; 228190225Srpaulo 229190225Srpaulo /* get the header type */ 230190225Srpaulo hdr_type = erf[(16 + (hdr_num * 8))]; 231190225Srpaulo hdr_num++; 232190225Srpaulo 233190225Srpaulo } while ( hdr_type & 0x80 ); 234190225Srpaulo 235190225Srpaulo return hdr_num; 236190225Srpaulo} 237190225Srpaulo 238127664Sbms/* 239127664Sbms * Read at most max_packets from the capture stream and call the callback 240127664Sbms * for each of them. Returns the number of packets handled, -1 if an 241127664Sbms * error occured, or -2 if we were told to break out of the loop. 242127664Sbms */ 243146768Ssamstatic int 244146768Ssamdag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 245146768Ssam{ 246276768Sdelphij struct pcap_dag *pd = p->priv; 247127664Sbms unsigned int processed = 0; 248276768Sdelphij int flags = pd->dag_offset_flags; 249127664Sbms unsigned int nonblocking = flags & DAGF_NONBLOCK; 250190225Srpaulo unsigned int num_ext_hdr = 0; 251127664Sbms 252162012Ssam /* Get the next bufferful of packets (if necessary). */ 253276768Sdelphij while (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size) { 254127664Sbms 255162012Ssam /* 256162012Ssam * Has "pcap_breakloop()" been called? 257162012Ssam */ 258162012Ssam if (p->break_loop) { 259127664Sbms /* 260162012Ssam * Yes - clear the flag that indicates that 261162012Ssam * it has, and return -2 to indicate that 262162012Ssam * we were told to break out of the loop. 263127664Sbms */ 264162012Ssam p->break_loop = 0; 265162012Ssam return -2; 266162012Ssam } 267127664Sbms 268162012Ssam#ifdef HAVE_DAG_STREAMS_API 269162012Ssam /* dag_advance_stream() will block (unless nonblock is called) 270162012Ssam * until 64kB of data has accumulated. 271162012Ssam * If to_ms is set, it will timeout before 64kB has accumulated. 272162012Ssam * We wait for 64kB because processing a few packets at a time 273162012Ssam * can cause problems at high packet rates (>200kpps) due 274162012Ssam * to inefficiencies. 275162012Ssam * This does mean if to_ms is not specified the capture may 'hang' 276162012Ssam * for long periods if the data rate is extremely slow (<64kB/sec) 277162012Ssam * If non-block is specified it will return immediately. The user 278162012Ssam * is then responsible for efficiency. 279162012Ssam */ 280276768Sdelphij if ( NULL == (pd->dag_mem_top = dag_advance_stream(p->fd, pd->dag_stream, &(pd->dag_mem_bottom))) ) { 281190225Srpaulo return -1; 282190225Srpaulo } 283162012Ssam#else 284162012Ssam /* dag_offset does not support timeouts */ 285276768Sdelphij pd->dag_mem_top = dag_offset(p->fd, &(pd->dag_mem_bottom), flags); 286162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 287162012Ssam 288276768Sdelphij if (nonblocking && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) 289162012Ssam { 290162012Ssam /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ 291162012Ssam return 0; 292127664Sbms } 293162012Ssam 294162012Ssam if(!nonblocking && 295276768Sdelphij pd->dag_timeout && 296276768Sdelphij (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) 297162012Ssam { 298162012Ssam /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ 299162012Ssam return 0; 300162012Ssam } 301162012Ssam 302162012Ssam } 303146768Ssam 304162012Ssam /* Process the packets. */ 305276768Sdelphij while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) { 306190225Srpaulo 307162012Ssam unsigned short packet_len = 0; 308162012Ssam int caplen = 0; 309162012Ssam struct pcap_pkthdr pcap_header; 310190225Srpaulo 311162012Ssam#ifdef HAVE_DAG_STREAMS_API 312276768Sdelphij dag_record_t *header = (dag_record_t *)(pd->dag_mem_bottom); 313162012Ssam#else 314276768Sdelphij dag_record_t *header = (dag_record_t *)(pd->dag_mem_base + pd->dag_mem_bottom); 315162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 316162012Ssam 317190225Srpaulo u_char *dp = ((u_char *)header); /* + dag_record_size; */ 318162012Ssam unsigned short rlen; 319127664Sbms 320162012Ssam /* 321162012Ssam * Has "pcap_breakloop()" been called? 322162012Ssam */ 323162012Ssam if (p->break_loop) { 324127664Sbms /* 325162012Ssam * Yes - clear the flag that indicates that 326162012Ssam * it has, and return -2 to indicate that 327162012Ssam * we were told to break out of the loop. 328127664Sbms */ 329162012Ssam p->break_loop = 0; 330162012Ssam return -2; 331162012Ssam } 332127664Sbms 333162012Ssam rlen = ntohs(header->rlen); 334162012Ssam if (rlen < dag_record_size) 335162012Ssam { 336162012Ssam strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); 337162012Ssam return -1; 338162012Ssam } 339276768Sdelphij pd->dag_mem_bottom += rlen; 340162012Ssam 341162012Ssam /* Count lost packets. */ 342190225Srpaulo switch((header->type & 0x7f)) { 343190225Srpaulo /* in these types the color value overwrites the lctr */ 344162012Ssam case TYPE_COLOR_HDLC_POS: 345162012Ssam case TYPE_COLOR_ETH: 346172677Smlaier case TYPE_DSM_COLOR_HDLC_POS: 347172677Smlaier case TYPE_DSM_COLOR_ETH: 348172677Smlaier case TYPE_COLOR_MC_HDLC_POS: 349190225Srpaulo case TYPE_COLOR_HASH_ETH: 350190225Srpaulo case TYPE_COLOR_HASH_POS: 351172677Smlaier break; 352172677Smlaier 353162012Ssam default: 354127664Sbms if (header->lctr) { 355276768Sdelphij if (pd->stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { 356276768Sdelphij pd->stat.ps_drop = UINT_MAX; 357127664Sbms } else { 358276768Sdelphij pd->stat.ps_drop += ntohs(header->lctr); 359127664Sbms } 360127664Sbms } 361162012Ssam } 362190225Srpaulo 363190225Srpaulo if ((header->type & 0x7f) == TYPE_PAD) { 364190225Srpaulo continue; 365190225Srpaulo } 366127664Sbms 367190225Srpaulo num_ext_hdr = dag_erf_ext_header_count(dp, rlen); 368190225Srpaulo 369190225Srpaulo /* ERF encapsulation */ 370190225Srpaulo /* The Extensible Record Format is not dropped for this kind of encapsulation, 371190225Srpaulo * and will be handled as a pseudo header by the decoding application. 372190225Srpaulo * The information carried in the ERF header and in the optional subheader (if present) 373190225Srpaulo * could be merged with the libpcap information, to offer a better decoding. 374190225Srpaulo * The packet length is 375190225Srpaulo * o the length of the packet on the link (header->wlen), 376190225Srpaulo * o plus the length of the ERF header (dag_record_size), as the length of the 377190225Srpaulo * pseudo header will be adjusted during the decoding, 378190225Srpaulo * o plus the length of the optional subheader (if present). 379190225Srpaulo * 380190225Srpaulo * The capture length is header.rlen and the byte stuffing for alignment will be dropped 381190225Srpaulo * if the capture length is greater than the packet length. 382190225Srpaulo */ 383190225Srpaulo if (p->linktype == DLT_ERF) { 384190225Srpaulo packet_len = ntohs(header->wlen) + dag_record_size; 385190225Srpaulo caplen = rlen; 386190225Srpaulo switch ((header->type & 0x7f)) { 387190225Srpaulo case TYPE_MC_AAL5: 388190225Srpaulo case TYPE_MC_ATM: 389190225Srpaulo case TYPE_MC_HDLC: 390214518Srpaulo case TYPE_MC_RAW_CHANNEL: 391214518Srpaulo case TYPE_MC_RAW: 392214518Srpaulo case TYPE_MC_AAL2: 393214518Srpaulo case TYPE_COLOR_MC_HDLC_POS: 394190225Srpaulo packet_len += 4; /* MC header */ 395190225Srpaulo break; 396190225Srpaulo 397190225Srpaulo case TYPE_COLOR_HASH_ETH: 398190225Srpaulo case TYPE_DSM_COLOR_ETH: 399190225Srpaulo case TYPE_COLOR_ETH: 400190225Srpaulo case TYPE_ETH: 401190225Srpaulo packet_len += 2; /* ETH header */ 402190225Srpaulo break; 403190225Srpaulo } /* switch type */ 404190225Srpaulo 405190225Srpaulo /* Include ERF extension headers */ 406190225Srpaulo packet_len += (8 * num_ext_hdr); 407190225Srpaulo 408190225Srpaulo if (caplen > packet_len) { 409190225Srpaulo caplen = packet_len; 410190225Srpaulo } 411190225Srpaulo } else { 412190225Srpaulo /* Other kind of encapsulation according to the header Type */ 413190225Srpaulo 414190225Srpaulo /* Skip over generic ERF header */ 415190225Srpaulo dp += dag_record_size; 416190225Srpaulo /* Skip over extension headers */ 417190225Srpaulo dp += 8 * num_ext_hdr; 418190225Srpaulo 419190225Srpaulo switch((header->type & 0x7f)) { 420190225Srpaulo case TYPE_ATM: 421190225Srpaulo case TYPE_AAL5: 422190225Srpaulo if (header->type == TYPE_AAL5) { 423190225Srpaulo packet_len = ntohs(header->wlen); 424190225Srpaulo caplen = rlen - dag_record_size; 425190225Srpaulo } 426190225Srpaulo case TYPE_MC_ATM: 427190225Srpaulo if (header->type == TYPE_MC_ATM) { 428190225Srpaulo caplen = packet_len = ATM_CELL_SIZE; 429190225Srpaulo dp+=4; 430190225Srpaulo } 431190225Srpaulo case TYPE_MC_AAL5: 432190225Srpaulo if (header->type == TYPE_MC_AAL5) { 433190225Srpaulo packet_len = ntohs(header->wlen); 434190225Srpaulo caplen = rlen - dag_record_size - 4; 435190225Srpaulo dp+=4; 436190225Srpaulo } 437190225Srpaulo if (header->type == TYPE_ATM) { 438190225Srpaulo caplen = packet_len = ATM_CELL_SIZE; 439190225Srpaulo } 440190225Srpaulo if (p->linktype == DLT_SUNATM) { 441190225Srpaulo struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; 442190225Srpaulo unsigned long rawatm; 443190225Srpaulo 444190225Srpaulo rawatm = ntohl(*((unsigned long *)dp)); 445190225Srpaulo sunatm->vci = htons((rawatm >> 4) & 0xffff); 446190225Srpaulo sunatm->vpi = (rawatm >> 20) & 0x00ff; 447190225Srpaulo sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | 448190225Srpaulo ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : 449190225Srpaulo ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : 450190225Srpaulo ((dp[ATM_HDR_SIZE] == 0xaa && 451190225Srpaulo dp[ATM_HDR_SIZE+1] == 0xaa && 452190225Srpaulo dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); 453190225Srpaulo 454190225Srpaulo } else { 455190225Srpaulo packet_len -= ATM_HDR_SIZE; 456190225Srpaulo caplen -= ATM_HDR_SIZE; 457190225Srpaulo dp += ATM_HDR_SIZE; 458190225Srpaulo } 459190225Srpaulo break; 460190225Srpaulo 461190225Srpaulo case TYPE_COLOR_HASH_ETH: 462190225Srpaulo case TYPE_DSM_COLOR_ETH: 463190225Srpaulo case TYPE_COLOR_ETH: 464190225Srpaulo case TYPE_ETH: 465190225Srpaulo packet_len = ntohs(header->wlen); 466276768Sdelphij packet_len -= (pd->dag_fcs_bits >> 3); 467190225Srpaulo caplen = rlen - dag_record_size - 2; 468190225Srpaulo if (caplen > packet_len) { 469190225Srpaulo caplen = packet_len; 470190225Srpaulo } 471190225Srpaulo dp += 2; 472190225Srpaulo break; 473190225Srpaulo 474190225Srpaulo case TYPE_COLOR_HASH_POS: 475190225Srpaulo case TYPE_DSM_COLOR_HDLC_POS: 476190225Srpaulo case TYPE_COLOR_HDLC_POS: 477190225Srpaulo case TYPE_HDLC_POS: 478190225Srpaulo packet_len = ntohs(header->wlen); 479276768Sdelphij packet_len -= (pd->dag_fcs_bits >> 3); 480190225Srpaulo caplen = rlen - dag_record_size; 481190225Srpaulo if (caplen > packet_len) { 482190225Srpaulo caplen = packet_len; 483190225Srpaulo } 484190225Srpaulo break; 485190225Srpaulo 486190225Srpaulo case TYPE_COLOR_MC_HDLC_POS: 487190225Srpaulo case TYPE_MC_HDLC: 488190225Srpaulo packet_len = ntohs(header->wlen); 489276768Sdelphij packet_len -= (pd->dag_fcs_bits >> 3); 490190225Srpaulo caplen = rlen - dag_record_size - 4; 491190225Srpaulo if (caplen > packet_len) { 492190225Srpaulo caplen = packet_len; 493190225Srpaulo } 494190225Srpaulo /* jump the MC_HDLC_HEADER */ 495190225Srpaulo dp += 4; 496190225Srpaulo#ifdef DLT_MTP2_WITH_PHDR 497190225Srpaulo if (p->linktype == DLT_MTP2_WITH_PHDR) { 498190225Srpaulo /* Add the MTP2 Pseudo Header */ 499190225Srpaulo caplen += MTP2_HDR_LEN; 500190225Srpaulo packet_len += MTP2_HDR_LEN; 501190225Srpaulo 502190225Srpaulo TempPkt[MTP2_SENT_OFFSET] = 0; 503190225Srpaulo TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN; 504190225Srpaulo *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01); 505190225Srpaulo *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff); 506190225Srpaulo memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen); 507190225Srpaulo dp = TempPkt; 508190225Srpaulo } 509190225Srpaulo#endif 510190225Srpaulo break; 511190225Srpaulo 512190225Srpaulo case TYPE_IPV4: 513214518Srpaulo case TYPE_IPV6: 514190225Srpaulo packet_len = ntohs(header->wlen); 515190225Srpaulo caplen = rlen - dag_record_size; 516190225Srpaulo if (caplen > packet_len) { 517190225Srpaulo caplen = packet_len; 518190225Srpaulo } 519190225Srpaulo break; 520190225Srpaulo 521214518Srpaulo /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */ 522214518Srpaulo case TYPE_MC_RAW: 523214518Srpaulo case TYPE_MC_RAW_CHANNEL: 524214518Srpaulo case TYPE_IP_COUNTER: 525214518Srpaulo case TYPE_TCP_FLOW_COUNTER: 526214518Srpaulo case TYPE_INFINIBAND: 527214518Srpaulo case TYPE_RAW_LINK: 528214518Srpaulo case TYPE_INFINIBAND_LINK: 529190225Srpaulo default: 530190225Srpaulo /* Unhandled ERF type. 531190225Srpaulo * Ignore rather than generating error 532190225Srpaulo */ 533190225Srpaulo continue; 534190225Srpaulo } /* switch type */ 535190225Srpaulo 536190225Srpaulo /* Skip over extension headers */ 537190225Srpaulo caplen -= (8 * num_ext_hdr); 538190225Srpaulo 539190225Srpaulo } /* ERF encapsulation */ 540190225Srpaulo 541190225Srpaulo if (caplen > p->snapshot) 542190225Srpaulo caplen = p->snapshot; 543190225Srpaulo 544162012Ssam /* Run the packet filter if there is one. */ 545162012Ssam if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { 546190225Srpaulo 547162012Ssam /* convert between timestamp formats */ 548162012Ssam register unsigned long long ts; 549127664Sbms 550162012Ssam if (IS_BIGENDIAN()) { 551172677Smlaier ts = SWAPLL(header->ts); 552162012Ssam } else { 553162012Ssam ts = header->ts; 554162012Ssam } 555127664Sbms 556162012Ssam pcap_header.ts.tv_sec = ts >> 32; 557162012Ssam ts = (ts & 0xffffffffULL) * 1000000; 558162012Ssam ts += 0x80000000; /* rounding */ 559162012Ssam pcap_header.ts.tv_usec = ts >> 32; 560162012Ssam if (pcap_header.ts.tv_usec >= 1000000) { 561162012Ssam pcap_header.ts.tv_usec -= 1000000; 562162012Ssam pcap_header.ts.tv_sec++; 563162012Ssam } 564127664Sbms 565162012Ssam /* Fill in our own header data */ 566162012Ssam pcap_header.caplen = caplen; 567162012Ssam pcap_header.len = packet_len; 568146768Ssam 569162012Ssam /* Count the packet. */ 570276768Sdelphij pd->stat.ps_recv++; 571146768Ssam 572162012Ssam /* Call the user supplied callback function */ 573162012Ssam callback(user, &pcap_header, dp); 574146768Ssam 575162012Ssam /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ 576162012Ssam processed++; 577276768Sdelphij if (processed == cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) 578162012Ssam { 579162012Ssam /* Reached the user-specified limit. */ 580162012Ssam return cnt; 581127664Sbms } 582127664Sbms } 583162012Ssam } 584127664Sbms 585127664Sbms return processed; 586127664Sbms} 587127664Sbms 588146768Ssamstatic int 589146768Ssamdag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 590146768Ssam{ 591146768Ssam strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", 592146768Ssam PCAP_ERRBUF_SIZE); 593146768Ssam return (-1); 594146768Ssam} 595146768Ssam 596127664Sbms/* 597127664Sbms * Get a handle for a live capture from the given DAG device. Passing a NULL 598127664Sbms * device will result in a failure. The promisc flag is ignored because DAG 599190225Srpaulo * cards are always promiscuous. The to_ms parameter is used in setting the 600190225Srpaulo * API polling parameters. 601127664Sbms * 602172677Smlaier * snaplen is now also ignored, until we get per-stream slen support. Set 603190225Srpaulo * slen with approprite DAG tool BEFORE pcap_activate(). 604172677Smlaier * 605127664Sbms * See also pcap(3). 606127664Sbms */ 607190225Srpaulostatic int dag_activate(pcap_t* handle) 608146768Ssam{ 609276768Sdelphij struct pcap_dag *handlep = handle->priv; 610190225Srpaulo#if 0 611146768Ssam char conf[30]; /* dag configure string */ 612190225Srpaulo#endif 613146768Ssam char *s; 614146768Ssam int n; 615146768Ssam daginf_t* daginf; 616172677Smlaier char * newDev = NULL; 617190225Srpaulo char * device = handle->opt.source; 618162012Ssam#ifdef HAVE_DAG_STREAMS_API 619162012Ssam uint32_t mindata; 620162012Ssam struct timeval maxwait; 621162012Ssam struct timeval poll; 622162012Ssam#endif 623162012Ssam 624146768Ssam if (device == NULL) { 625190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); 626190225Srpaulo return -1; 627146768Ssam } 628127664Sbms 629146768Ssam /* Initialize some components of the pcap structure. */ 630127664Sbms 631172677Smlaier#ifdef HAVE_DAG_STREAMS_API 632162012Ssam newDev = (char *)malloc(strlen(device) + 16); 633172677Smlaier if (newDev == NULL) { 634190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); 635172677Smlaier goto fail; 636172677Smlaier } 637162012Ssam 638162012Ssam /* Parse input name to get dag device and stream number if provided */ 639276768Sdelphij if (dag_parse_name(device, newDev, strlen(device) + 16, &handlep->dag_stream) < 0) { 640190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: %s\n", pcap_strerror(errno)); 641162012Ssam goto fail; 642162012Ssam } 643162012Ssam device = newDev; 644162012Ssam 645276768Sdelphij if (handlep->dag_stream%2) { 646190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture\n"); 647162012Ssam goto fail; 648162012Ssam } 649162012Ssam#else 650172677Smlaier if (strncmp(device, "/dev/", 5) != 0) { 651172677Smlaier newDev = (char *)malloc(strlen(device) + 5); 652172677Smlaier if (newDev == NULL) { 653190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); 654172677Smlaier goto fail; 655172677Smlaier } 656172677Smlaier strcpy(newDev, "/dev/"); 657172677Smlaier strcat(newDev, device); 658146768Ssam device = newDev; 659146768Ssam } 660162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 661127664Sbms 662146768Ssam /* setup device parameters */ 663146768Ssam if((handle->fd = dag_open((char *)device)) < 0) { 664190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno)); 665146768Ssam goto fail; 666146768Ssam } 667127664Sbms 668162012Ssam#ifdef HAVE_DAG_STREAMS_API 669162012Ssam /* Open requested stream. Can fail if already locked or on error */ 670276768Sdelphij if (dag_attach_stream(handle->fd, handlep->dag_stream, 0, 0) < 0) { 671190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s\n", pcap_strerror(errno)); 672172677Smlaier goto failclose; 673162012Ssam } 674162012Ssam 675162012Ssam /* Set up default poll parameters for stream 676162012Ssam * Can be overridden by pcap_set_nonblock() 677162012Ssam */ 678276768Sdelphij if (dag_get_stream_poll(handle->fd, handlep->dag_stream, 679162012Ssam &mindata, &maxwait, &poll) < 0) { 680190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); 681172677Smlaier goto faildetach; 682162012Ssam } 683162012Ssam 684276768Sdelphij if (handle->opt.immediate) { 685276768Sdelphij /* Call callback immediately. 686276768Sdelphij * XXX - is this the right way to handle this? 687276768Sdelphij */ 688276768Sdelphij mindata = 0; 689276768Sdelphij } else { 690276768Sdelphij /* Amount of data to collect in Bytes before calling callbacks. 691276768Sdelphij * Important for efficiency, but can introduce latency 692276768Sdelphij * at low packet rates if to_ms not set! 693276768Sdelphij */ 694276768Sdelphij mindata = 65536; 695276768Sdelphij } 696162012Ssam 697276768Sdelphij /* Obey opt.timeout (was to_ms) if supplied. This is a good idea! 698162012Ssam * Recommend 10-100ms. Calls will time out even if no data arrived. 699162012Ssam */ 700276768Sdelphij maxwait.tv_sec = handle->opt.timeout/1000; 701276768Sdelphij maxwait.tv_usec = (handle->opt.timeout%1000) * 1000; 702162012Ssam 703276768Sdelphij if (dag_set_stream_poll(handle->fd, handlep->dag_stream, 704162012Ssam mindata, &maxwait, &poll) < 0) { 705190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); 706172677Smlaier goto faildetach; 707162012Ssam } 708162012Ssam 709162012Ssam#else 710276768Sdelphij if((handlep->dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { 711190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno)); 712172677Smlaier goto failclose; 713162012Ssam } 714162012Ssam 715162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 716162012Ssam 717172677Smlaier /* XXX Not calling dag_configure() to set slen; this is unsafe in 718172677Smlaier * multi-stream environments as the gpp config is global. 719172677Smlaier * Once the firmware provides 'per-stream slen' this can be supported 720172677Smlaier * again via the Config API without side-effects */ 721172677Smlaier#if 0 722146768Ssam /* set the card snap length to the specified snaplen parameter */ 723172677Smlaier /* This is a really bad idea, as different cards have different 724172677Smlaier * valid slen ranges. Should fix in Config API. */ 725190225Srpaulo if (handle->snapshot == 0 || handle->snapshot > MAX_DAG_SNAPLEN) { 726190225Srpaulo handle->snapshot = MAX_DAG_SNAPLEN; 727146768Ssam } else if (snaplen < MIN_DAG_SNAPLEN) { 728190225Srpaulo handle->snapshot = MIN_DAG_SNAPLEN; 729146768Ssam } 730146768Ssam /* snap len has to be a multiple of 4 */ 731146768Ssam snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); 732127664Sbms 733146768Ssam if(dag_configure(handle->fd, conf) < 0) { 734190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno)); 735172677Smlaier goto faildetach; 736146768Ssam } 737172677Smlaier#endif 738172677Smlaier 739162012Ssam#ifdef HAVE_DAG_STREAMS_API 740276768Sdelphij if(dag_start_stream(handle->fd, handlep->dag_stream) < 0) { 741190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s\n", device, pcap_strerror(errno)); 742172677Smlaier goto faildetach; 743146768Ssam } 744162012Ssam#else 745146768Ssam if(dag_start(handle->fd) < 0) { 746190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno)); 747172677Smlaier goto failclose; 748146768Ssam } 749162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 750127664Sbms 751146768Ssam /* 752146768Ssam * Important! You have to ensure bottom is properly 753146768Ssam * initialized to zero on startup, it won't give you 754146768Ssam * a compiler warning if you make this mistake! 755146768Ssam */ 756276768Sdelphij handlep->dag_mem_bottom = 0; 757276768Sdelphij handlep->dag_mem_top = 0; 758127664Sbms 759190225Srpaulo /* 760190225Srpaulo * Find out how many FCS bits we should strip. 761190225Srpaulo * First, query the card to see if it strips the FCS. 762190225Srpaulo */ 763146768Ssam daginf = dag_info(handle->fd); 764190225Srpaulo if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) { 765146768Ssam /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ 766276768Sdelphij handlep->dag_fcs_bits = 0; 767127664Sbms 768190225Srpaulo /* Note that no FCS will be supplied. */ 769190225Srpaulo handle->linktype_ext = LT_FCS_DATALINK_EXT(0); 770190225Srpaulo } else { 771190225Srpaulo /* 772190225Srpaulo * Start out assuming it's 32 bits. 773190225Srpaulo */ 774276768Sdelphij handlep->dag_fcs_bits = 32; 775190225Srpaulo 776190225Srpaulo /* Allow an environment variable to override. */ 777190225Srpaulo if ((s = getenv("ERF_FCS_BITS")) != NULL) { 778190225Srpaulo if ((n = atoi(s)) == 0 || n == 16 || n == 32) { 779276768Sdelphij handlep->dag_fcs_bits = n; 780190225Srpaulo } else { 781190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 782190225Srpaulo "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n); 783190225Srpaulo goto failstop; 784190225Srpaulo } 785146768Ssam } 786190225Srpaulo 787190225Srpaulo /* 788190225Srpaulo * Did the user request that they not be stripped? 789190225Srpaulo */ 790190225Srpaulo if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) { 791190225Srpaulo /* Yes. Note the number of bytes that will be 792190225Srpaulo supplied. */ 793276768Sdelphij handle->linktype_ext = LT_FCS_DATALINK_EXT(handlep->dag_fcs_bits/16); 794190225Srpaulo 795190225Srpaulo /* And don't strip them. */ 796276768Sdelphij handlep->dag_fcs_bits = 0; 797190225Srpaulo } 798146768Ssam } 799127664Sbms 800276768Sdelphij handlep->dag_timeout = handle->opt.timeout; 801127664Sbms 802146768Ssam handle->linktype = -1; 803190225Srpaulo if (dag_get_datalink(handle) < 0) 804172677Smlaier goto failstop; 805146768Ssam 806146768Ssam handle->bufsize = 0; 807127664Sbms 808146768Ssam if (new_pcap_dag(handle) < 0) { 809190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno)); 810172677Smlaier goto failstop; 811146768Ssam } 812127664Sbms 813146768Ssam /* 814162012Ssam * "select()" and "poll()" don't work on DAG device descriptors. 815146768Ssam */ 816146768Ssam handle->selectable_fd = -1; 817146768Ssam 818172677Smlaier if (newDev != NULL) { 819172677Smlaier free((char *)newDev); 820172677Smlaier } 821127664Sbms 822146768Ssam handle->read_op = dag_read; 823146768Ssam handle->inject_op = dag_inject; 824146768Ssam handle->setfilter_op = dag_setfilter; 825147894Ssam handle->setdirection_op = NULL; /* Not implemented.*/ 826146768Ssam handle->set_datalink_op = dag_set_datalink; 827146768Ssam handle->getnonblock_op = pcap_getnonblock_fd; 828146768Ssam handle->setnonblock_op = dag_setnonblock; 829146768Ssam handle->stats_op = dag_stats; 830190225Srpaulo handle->cleanup_op = dag_platform_cleanup; 831276768Sdelphij handlep->stat.ps_drop = 0; 832276768Sdelphij handlep->stat.ps_recv = 0; 833276768Sdelphij handlep->stat.ps_ifdrop = 0; 834190225Srpaulo return 0; 835127664Sbms 836172677Smlaier#ifdef HAVE_DAG_STREAMS_API 837172677Smlaierfailstop: 838276768Sdelphij if (dag_stop_stream(handle->fd, handlep->dag_stream) < 0) { 839190225Srpaulo fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); 840172677Smlaier } 841172677Smlaier 842172677Smlaierfaildetach: 843276768Sdelphij if (dag_detach_stream(handle->fd, handlep->dag_stream) < 0) 844190225Srpaulo fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); 845190225Srpaulo#else 846172677Smlaierfailstop: 847190225Srpaulo if (dag_stop(handle->fd) < 0) 848190225Srpaulo fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 849172677Smlaier#endif /* HAVE_DAG_STREAMS_API */ 850172677Smlaier 851172677Smlaierfailclose: 852190225Srpaulo if (dag_close(handle->fd) < 0) 853190225Srpaulo fprintf(stderr,"dag_close: %s\n", strerror(errno)); 854190225Srpaulo delete_pcap_dag(handle); 855190225Srpaulo 856127664Sbmsfail: 857190225Srpaulo pcap_cleanup_live_common(handle); 858162012Ssam if (newDev != NULL) { 859162012Ssam free((char *)newDev); 860146768Ssam } 861127664Sbms 862190225Srpaulo return PCAP_ERROR; 863127664Sbms} 864127664Sbms 865251129Sdelphijpcap_t *dag_create(const char *device, char *ebuf, int *is_ours) 866190225Srpaulo{ 867251129Sdelphij const char *cp; 868251129Sdelphij char *cpend; 869251129Sdelphij long devnum; 870190225Srpaulo pcap_t *p; 871276768Sdelphij#ifdef HAVE_DAG_STREAMS_API 872276768Sdelphij long stream = 0; 873276768Sdelphij#endif 874190225Srpaulo 875251129Sdelphij /* Does this look like a DAG device? */ 876251129Sdelphij cp = strrchr(device, '/'); 877251129Sdelphij if (cp == NULL) 878251129Sdelphij cp = device; 879251129Sdelphij /* Does it begin with "dag"? */ 880251129Sdelphij if (strncmp(cp, "dag", 3) != 0) { 881251129Sdelphij /* Nope, doesn't begin with "dag" */ 882251129Sdelphij *is_ours = 0; 883251129Sdelphij return NULL; 884251129Sdelphij } 885276768Sdelphij /* Yes - is "dag" followed by a number from 0 to DAG_MAX_BOARDS-1 */ 886251129Sdelphij cp += 3; 887251129Sdelphij devnum = strtol(cp, &cpend, 10); 888276768Sdelphij#ifdef HAVE_DAG_STREAMS_API 889276768Sdelphij if (*cpend == ':') { 890276768Sdelphij /* Followed by a stream number. */ 891276768Sdelphij stream = strtol(++cpend, &cpend, 10); 892276768Sdelphij } 893276768Sdelphij#endif 894251129Sdelphij if (cpend == cp || *cpend != '\0') { 895251129Sdelphij /* Not followed by a number. */ 896251129Sdelphij *is_ours = 0; 897251129Sdelphij return NULL; 898251129Sdelphij } 899276768Sdelphij if (devnum < 0 || devnum >= DAG_MAX_BOARDS) { 900251129Sdelphij /* Followed by a non-valid number. */ 901251129Sdelphij *is_ours = 0; 902251129Sdelphij return NULL; 903251129Sdelphij } 904276768Sdelphij#ifdef HAVE_DAG_STREAMS_API 905276768Sdelphij if (stream <0 || stream >= DAG_STREAM_MAX) { 906276768Sdelphij /* Followed by a non-valid stream number. */ 907276768Sdelphij *is_ours = 0; 908276768Sdelphij return NULL; 909276768Sdelphij } 910276768Sdelphij#endif 911251129Sdelphij 912251129Sdelphij /* OK, it's probably ours. */ 913251129Sdelphij *is_ours = 1; 914251129Sdelphij 915276768Sdelphij p = pcap_create_common(device, ebuf, sizeof (struct pcap_dag)); 916190225Srpaulo if (p == NULL) 917190225Srpaulo return NULL; 918190225Srpaulo 919190225Srpaulo p->activate_op = dag_activate; 920190225Srpaulo return p; 921190225Srpaulo} 922190225Srpaulo 923146768Ssamstatic int 924146768Ssamdag_stats(pcap_t *p, struct pcap_stat *ps) { 925276768Sdelphij struct pcap_dag *pd = p->priv; 926276768Sdelphij 927146768Ssam /* This needs to be filled out correctly. Hopefully a dagapi call will 928146768Ssam provide all necessary information. 929146768Ssam */ 930276768Sdelphij /*pd->stat.ps_recv = 0;*/ 931276768Sdelphij /*pd->stat.ps_drop = 0;*/ 932146768Ssam 933276768Sdelphij *ps = pd->stat; 934127664Sbms 935146768Ssam return 0; 936127664Sbms} 937127664Sbms 938127664Sbms/* 939190225Srpaulo * Previously we just generated a list of all possible names and let 940190225Srpaulo * pcap_add_if() attempt to open each one, but with streams this adds up 941190225Srpaulo * to 81 possibilities which is inefficient. 942190225Srpaulo * 943190225Srpaulo * Since we know more about the devices we can prune the tree here. 944190225Srpaulo * pcap_add_if() will still retest each device but the total number of 945190225Srpaulo * open attempts will still be much less than the naive approach. 946127664Sbms */ 947127664Sbmsint 948251129Sdelphijdag_findalldevs(pcap_if_t **devlistp, char *errbuf) 949127664Sbms{ 950162012Ssam char name[12]; /* XXX - pick a size */ 951146768Ssam int ret = 0; 952162012Ssam int c; 953190225Srpaulo char dagname[DAGNAME_BUFSIZE]; 954190225Srpaulo int dagstream; 955190225Srpaulo int dagfd; 956127664Sbms 957276768Sdelphij /* Try all the DAGs 0-DAG_MAX_BOARDS */ 958276768Sdelphij for (c = 0; c < DAG_MAX_BOARDS; c++) { 959162012Ssam snprintf(name, 12, "dag%d", c); 960190225Srpaulo if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream)) 961190225Srpaulo { 962190225Srpaulo return -1; 963146768Ssam } 964190225Srpaulo if ( (dagfd = dag_open(dagname)) >= 0 ) { 965190225Srpaulo if (pcap_add_if(devlistp, name, 0, NULL, errbuf) == -1) { 966190225Srpaulo /* 967190225Srpaulo * Failure. 968190225Srpaulo */ 969190225Srpaulo ret = -1; 970190225Srpaulo } 971162012Ssam#ifdef HAVE_DAG_STREAMS_API 972190225Srpaulo { 973190225Srpaulo int stream, rxstreams; 974190225Srpaulo rxstreams = dag_rx_get_stream_count(dagfd); 975235426Sdelphij for(stream=0;stream<DAG_STREAM_MAX;stream+=2) { 976190225Srpaulo if (0 == dag_attach_stream(dagfd, stream, 0, 0)) { 977190225Srpaulo dag_detach_stream(dagfd, stream); 978190225Srpaulo 979190225Srpaulo snprintf(name, 10, "dag%d:%d", c, stream); 980190225Srpaulo if (pcap_add_if(devlistp, name, 0, NULL, errbuf) == -1) { 981190225Srpaulo /* 982190225Srpaulo * Failure. 983190225Srpaulo */ 984190225Srpaulo ret = -1; 985190225Srpaulo } 986235426Sdelphij 987235426Sdelphij rxstreams--; 988235426Sdelphij if(rxstreams <= 0) { 989235426Sdelphij break; 990235426Sdelphij } 991190225Srpaulo } 992190225Srpaulo } 993190225Srpaulo } 994190225Srpaulo#endif /* HAVE_DAG_STREAMS_API */ 995190225Srpaulo dag_close(dagfd); 996146768Ssam } 997190225Srpaulo 998146768Ssam } 999146768Ssam return (ret); 1000127664Sbms} 1001127664Sbms 1002127664Sbms/* 1003127664Sbms * Installs the given bpf filter program in the given pcap structure. There is 1004127664Sbms * no attempt to store the filter in kernel memory as that is not supported 1005127664Sbms * with DAG cards. 1006127664Sbms */ 1007146768Ssamstatic int 1008146768Ssamdag_setfilter(pcap_t *p, struct bpf_program *fp) 1009146768Ssam{ 1010146768Ssam if (!p) 1011146768Ssam return -1; 1012146768Ssam if (!fp) { 1013146768Ssam strncpy(p->errbuf, "setfilter: No filter specified", 1014146768Ssam sizeof(p->errbuf)); 1015146768Ssam return -1; 1016146768Ssam } 1017127664Sbms 1018146768Ssam /* Make our private copy of the filter */ 1019127664Sbms 1020146768Ssam if (install_bpf_program(p, fp) < 0) 1021146768Ssam return -1; 1022127664Sbms 1023146768Ssam return (0); 1024127664Sbms} 1025127664Sbms 1026127664Sbmsstatic int 1027127664Sbmsdag_set_datalink(pcap_t *p, int dlt) 1028127664Sbms{ 1029146768Ssam p->linktype = dlt; 1030146768Ssam 1031127664Sbms return (0); 1032127664Sbms} 1033127664Sbms 1034127664Sbmsstatic int 1035127664Sbmsdag_setnonblock(pcap_t *p, int nonblock, char *errbuf) 1036127664Sbms{ 1037276768Sdelphij struct pcap_dag *pd = p->priv; 1038276768Sdelphij 1039127664Sbms /* 1040127664Sbms * Set non-blocking mode on the FD. 1041127664Sbms * XXX - is that necessary? If not, don't bother calling it, 1042127664Sbms * and have a "dag_getnonblock()" function that looks at 1043276768Sdelphij * "pd->dag_offset_flags". 1044127664Sbms */ 1045127664Sbms if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0) 1046127664Sbms return (-1); 1047162012Ssam#ifdef HAVE_DAG_STREAMS_API 1048162012Ssam { 1049162012Ssam uint32_t mindata; 1050162012Ssam struct timeval maxwait; 1051162012Ssam struct timeval poll; 1052162012Ssam 1053276768Sdelphij if (dag_get_stream_poll(p->fd, pd->dag_stream, 1054162012Ssam &mindata, &maxwait, &poll) < 0) { 1055162012Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); 1056162012Ssam return -1; 1057162012Ssam } 1058162012Ssam 1059162012Ssam /* Amount of data to collect in Bytes before calling callbacks. 1060162012Ssam * Important for efficiency, but can introduce latency 1061162012Ssam * at low packet rates if to_ms not set! 1062162012Ssam */ 1063162012Ssam if(nonblock) 1064162012Ssam mindata = 0; 1065162012Ssam else 1066162012Ssam mindata = 65536; 1067162012Ssam 1068276768Sdelphij if (dag_set_stream_poll(p->fd, pd->dag_stream, 1069162012Ssam mindata, &maxwait, &poll) < 0) { 1070162012Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); 1071162012Ssam return -1; 1072162012Ssam } 1073162012Ssam } 1074162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 1075127664Sbms if (nonblock) { 1076276768Sdelphij pd->dag_offset_flags |= DAGF_NONBLOCK; 1077127664Sbms } else { 1078276768Sdelphij pd->dag_offset_flags &= ~DAGF_NONBLOCK; 1079127664Sbms } 1080127664Sbms return (0); 1081127664Sbms} 1082127664Sbms 1083127664Sbmsstatic int 1084127664Sbmsdag_get_datalink(pcap_t *p) 1085127664Sbms{ 1086276768Sdelphij struct pcap_dag *pd = p->priv; 1087190225Srpaulo int index=0, dlt_index=0; 1088172677Smlaier uint8_t types[255]; 1089127664Sbms 1090172677Smlaier memset(types, 0, 255); 1091172677Smlaier 1092172677Smlaier if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) { 1093146768Ssam (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); 1094146768Ssam return (-1); 1095146768Ssam } 1096127664Sbms 1097172677Smlaier p->linktype = 0; 1098172677Smlaier 1099190225Srpaulo#ifdef HAVE_DAG_GET_STREAM_ERF_TYPES 1100172677Smlaier /* Get list of possible ERF types for this card */ 1101276768Sdelphij if (dag_get_stream_erf_types(p->fd, pd->dag_stream, types, 255) < 0) { 1102190225Srpaulo snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_stream_erf_types: %s", pcap_strerror(errno)); 1103190225Srpaulo return (-1); 1104190225Srpaulo } 1105190225Srpaulo 1106190225Srpaulo while (types[index]) { 1107190225Srpaulo 1108190225Srpaulo#elif defined HAVE_DAG_GET_ERF_TYPES 1109190225Srpaulo /* Get list of possible ERF types for this card */ 1110172677Smlaier if (dag_get_erf_types(p->fd, types, 255) < 0) { 1111172677Smlaier snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_erf_types: %s", pcap_strerror(errno)); 1112172677Smlaier return (-1); 1113172677Smlaier } 1114172677Smlaier 1115172677Smlaier while (types[index]) { 1116172677Smlaier#else 1117146768Ssam /* Check the type through a dagapi call. */ 1118172677Smlaier types[index] = dag_linktype(p->fd); 1119127664Sbms 1120172677Smlaier { 1121172677Smlaier#endif 1122190225Srpaulo switch((types[index] & 0x7f)) { 1123127664Sbms 1124172677Smlaier case TYPE_HDLC_POS: 1125172677Smlaier case TYPE_COLOR_HDLC_POS: 1126172677Smlaier case TYPE_DSM_COLOR_HDLC_POS: 1127190225Srpaulo case TYPE_COLOR_HASH_POS: 1128190225Srpaulo 1129172677Smlaier if (p->dlt_list != NULL) { 1130190225Srpaulo p->dlt_list[dlt_index++] = DLT_CHDLC; 1131190225Srpaulo p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; 1132190225Srpaulo p->dlt_list[dlt_index++] = DLT_FRELAY; 1133172677Smlaier } 1134172677Smlaier if(!p->linktype) 1135172677Smlaier p->linktype = DLT_CHDLC; 1136172677Smlaier break; 1137146768Ssam 1138172677Smlaier case TYPE_ETH: 1139172677Smlaier case TYPE_COLOR_ETH: 1140172677Smlaier case TYPE_DSM_COLOR_ETH: 1141190225Srpaulo case TYPE_COLOR_HASH_ETH: 1142172677Smlaier /* 1143172677Smlaier * This is (presumably) a real Ethernet capture; give it a 1144172677Smlaier * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 1145172677Smlaier * that an application can let you choose it, in case you're 1146172677Smlaier * capturing DOCSIS traffic that a Cisco Cable Modem 1147172677Smlaier * Termination System is putting out onto an Ethernet (it 1148172677Smlaier * doesn't put an Ethernet header onto the wire, it puts raw 1149172677Smlaier * DOCSIS frames out on the wire inside the low-level 1150172677Smlaier * Ethernet framing). 1151172677Smlaier */ 1152172677Smlaier if (p->dlt_list != NULL) { 1153190225Srpaulo p->dlt_list[dlt_index++] = DLT_EN10MB; 1154190225Srpaulo p->dlt_list[dlt_index++] = DLT_DOCSIS; 1155172677Smlaier } 1156172677Smlaier if(!p->linktype) 1157172677Smlaier p->linktype = DLT_EN10MB; 1158172677Smlaier break; 1159146768Ssam 1160172677Smlaier case TYPE_ATM: 1161172677Smlaier case TYPE_AAL5: 1162172677Smlaier case TYPE_MC_ATM: 1163172677Smlaier case TYPE_MC_AAL5: 1164172677Smlaier if (p->dlt_list != NULL) { 1165190225Srpaulo p->dlt_list[dlt_index++] = DLT_ATM_RFC1483; 1166190225Srpaulo p->dlt_list[dlt_index++] = DLT_SUNATM; 1167172677Smlaier } 1168172677Smlaier if(!p->linktype) 1169172677Smlaier p->linktype = DLT_ATM_RFC1483; 1170172677Smlaier break; 1171146768Ssam 1172172677Smlaier case TYPE_COLOR_MC_HDLC_POS: 1173172677Smlaier case TYPE_MC_HDLC: 1174172677Smlaier if (p->dlt_list != NULL) { 1175190225Srpaulo p->dlt_list[dlt_index++] = DLT_CHDLC; 1176190225Srpaulo p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; 1177190225Srpaulo p->dlt_list[dlt_index++] = DLT_FRELAY; 1178190225Srpaulo p->dlt_list[dlt_index++] = DLT_MTP2; 1179190225Srpaulo p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR; 1180190225Srpaulo p->dlt_list[dlt_index++] = DLT_LAPD; 1181172677Smlaier } 1182172677Smlaier if(!p->linktype) 1183172677Smlaier p->linktype = DLT_CHDLC; 1184172677Smlaier break; 1185146768Ssam 1186190225Srpaulo case TYPE_IPV4: 1187214518Srpaulo case TYPE_IPV6: 1188172677Smlaier if(!p->linktype) 1189190225Srpaulo p->linktype = DLT_RAW; 1190172677Smlaier break; 1191146768Ssam 1192190225Srpaulo case TYPE_LEGACY: 1193190225Srpaulo case TYPE_MC_RAW: 1194190225Srpaulo case TYPE_MC_RAW_CHANNEL: 1195190225Srpaulo case TYPE_IP_COUNTER: 1196190225Srpaulo case TYPE_TCP_FLOW_COUNTER: 1197190225Srpaulo case TYPE_INFINIBAND: 1198214518Srpaulo case TYPE_RAW_LINK: 1199214518Srpaulo case TYPE_INFINIBAND_LINK: 1200172677Smlaier default: 1201190225Srpaulo /* Libpcap cannot deal with these types yet */ 1202214518Srpaulo /* Add no 'native' DLTs, but still covered by DLT_ERF */ 1203190225Srpaulo break; 1204146768Ssam 1205172677Smlaier } /* switch */ 1206190225Srpaulo index++; 1207146768Ssam } 1208146768Ssam 1209190225Srpaulo p->dlt_list[dlt_index++] = DLT_ERF; 1210172677Smlaier 1211190225Srpaulo p->dlt_count = dlt_index; 1212190225Srpaulo 1213190225Srpaulo if(!p->linktype) 1214190225Srpaulo p->linktype = DLT_ERF; 1215190225Srpaulo 1216146768Ssam return p->linktype; 1217127664Sbms} 1218