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#ifndef lint 19127664Sbmsstatic const char rcsid[] _U_ = 20214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.39 2008-04-14 20:40:58 guy Exp $ (LBL)"; 21127664Sbms#endif 22127664Sbms 23127664Sbms#ifdef HAVE_CONFIG_H 24127664Sbms#include "config.h" 25127664Sbms#endif 26127664Sbms 27127664Sbms#include <sys/param.h> /* optionally get BSD define */ 28127664Sbms 29127664Sbms#include <stdlib.h> 30127664Sbms#include <string.h> 31127664Sbms#include <errno.h> 32127664Sbms 33127664Sbms#include "pcap-int.h" 34127664Sbms 35127664Sbms#include <ctype.h> 36127664Sbms#include <netinet/in.h> 37127664Sbms#include <sys/mman.h> 38127664Sbms#include <sys/socket.h> 39127664Sbms#include <sys/types.h> 40127664Sbms#include <unistd.h> 41127664Sbms 42127664Sbmsstruct mbuf; /* Squelch compiler warnings on some platforms for */ 43127664Sbmsstruct rtentry; /* declarations in <net/if.h> */ 44127664Sbms#include <net/if.h> 45127664Sbms 46146768Ssam#include "dagnew.h" 47146768Ssam#include "dagapi.h" 48127664Sbms 49190225Srpaulo#include "pcap-dag.h" 50190225Srpaulo 51252281Sdelphij/* 52252281Sdelphij * DAG devices have names beginning with "dag", followed by a number 53252281Sdelphij * from 0 to MAXDAG. 54252281Sdelphij */ 55252281Sdelphij#define MAXDAG 31 56252281Sdelphij 57146768Ssam#define ATM_CELL_SIZE 52 58146768Ssam#define ATM_HDR_SIZE 4 59127664Sbms 60172677Smlaier/* 61172677Smlaier * A header containing additional MTP information. 62172677Smlaier */ 63172677Smlaier#define MTP2_SENT_OFFSET 0 /* 1 byte */ 64172677Smlaier#define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */ 65172677Smlaier#define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */ 66172677Smlaier#define MTP2_HDR_LEN 4 /* length of the header */ 67172677Smlaier 68172677Smlaier#define MTP2_ANNEX_A_NOT_USED 0 69172677Smlaier#define MTP2_ANNEX_A_USED 1 70172677Smlaier#define MTP2_ANNEX_A_USED_UNKNOWN 2 71172677Smlaier 72146768Ssam/* SunATM pseudo header */ 73146768Ssamstruct sunatm_hdr { 74146768Ssam unsigned char flags; /* destination and traffic type */ 75146768Ssam unsigned char vpi; /* VPI */ 76146768Ssam unsigned short vci; /* VCI */ 77146768Ssam}; 78146768Ssam 79127664Sbmstypedef struct pcap_dag_node { 80146768Ssam struct pcap_dag_node *next; 81146768Ssam pcap_t *p; 82146768Ssam pid_t pid; 83127664Sbms} pcap_dag_node_t; 84127664Sbms 85127664Sbmsstatic pcap_dag_node_t *pcap_dags = NULL; 86127664Sbmsstatic int atexit_handler_installed = 0; 87127664Sbmsstatic const unsigned short endian_test_word = 0x0100; 88127664Sbms 89127664Sbms#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) 90127664Sbms 91172677Smlaier#define MAX_DAG_PACKET 65536 92172677Smlaier 93172677Smlaierstatic unsigned char TempPkt[MAX_DAG_PACKET]; 94172677Smlaier 95127664Sbmsstatic int dag_setfilter(pcap_t *p, struct bpf_program *fp); 96127664Sbmsstatic int dag_stats(pcap_t *p, struct pcap_stat *ps); 97127664Sbmsstatic int dag_set_datalink(pcap_t *p, int dlt); 98127664Sbmsstatic int dag_get_datalink(pcap_t *p); 99127664Sbmsstatic int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf); 100127664Sbms 101146768Ssamstatic void 102146768Ssamdelete_pcap_dag(pcap_t *p) 103146768Ssam{ 104146768Ssam pcap_dag_node_t *curr = NULL, *prev = NULL; 105127664Sbms 106146768Ssam for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { 107146768Ssam /* empty */ 108146768Ssam } 109127664Sbms 110146768Ssam if (curr != NULL && curr->p == p) { 111146768Ssam if (prev != NULL) { 112146768Ssam prev->next = curr->next; 113146768Ssam } else { 114146768Ssam pcap_dags = curr->next; 115146768Ssam } 116146768Ssam } 117127664Sbms} 118127664Sbms 119127664Sbms/* 120127664Sbms * Performs a graceful shutdown of the DAG card, frees dynamic memory held 121127664Sbms * in the pcap_t structure, and closes the file descriptor for the DAG card. 122127664Sbms */ 123127664Sbms 124146768Ssamstatic void 125190225Srpaulodag_platform_cleanup(pcap_t *p) 126146768Ssam{ 127162012Ssam 128162012Ssam if (p != NULL) { 129162012Ssam#ifdef HAVE_DAG_STREAMS_API 130162012Ssam if(dag_stop_stream(p->fd, p->md.dag_stream) < 0) 131162012Ssam fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); 132146768Ssam 133162012Ssam if(dag_detach_stream(p->fd, p->md.dag_stream) < 0) 134162012Ssam fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); 135127664Sbms#else 136146768Ssam if(dag_stop(p->fd) < 0) 137146768Ssam fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 138162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 139190225Srpaulo if(p->fd != -1) { 140190225Srpaulo if(dag_close(p->fd) < 0) 141190225Srpaulo fprintf(stderr,"dag_close: %s\n", strerror(errno)); 142190225Srpaulo p->fd = -1; 143190225Srpaulo } 144190225Srpaulo delete_pcap_dag(p); 145190225Srpaulo pcap_cleanup_live_common(p); 146146768Ssam } 147146768Ssam /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ 148127664Sbms} 149127664Sbms 150146768Ssamstatic void 151146768Ssamatexit_handler(void) 152146768Ssam{ 153146768Ssam while (pcap_dags != NULL) { 154146768Ssam if (pcap_dags->pid == getpid()) { 155190225Srpaulo dag_platform_cleanup(pcap_dags->p); 156146768Ssam } else { 157146768Ssam delete_pcap_dag(pcap_dags->p); 158146768Ssam } 159146768Ssam } 160127664Sbms} 161127664Sbms 162146768Ssamstatic int 163146768Ssamnew_pcap_dag(pcap_t *p) 164146768Ssam{ 165146768Ssam pcap_dag_node_t *node = NULL; 166127664Sbms 167146768Ssam if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { 168146768Ssam return -1; 169146768Ssam } 170127664Sbms 171146768Ssam if (!atexit_handler_installed) { 172146768Ssam atexit(atexit_handler); 173146768Ssam atexit_handler_installed = 1; 174146768Ssam } 175127664Sbms 176146768Ssam node->next = pcap_dags; 177146768Ssam node->p = p; 178146768Ssam node->pid = getpid(); 179127664Sbms 180146768Ssam pcap_dags = node; 181127664Sbms 182146768Ssam return 0; 183127664Sbms} 184127664Sbms 185190225Srpaulostatic unsigned int 186190225Srpaulodag_erf_ext_header_count(uint8_t * erf, size_t len) 187190225Srpaulo{ 188190225Srpaulo uint32_t hdr_num = 0; 189190225Srpaulo uint8_t hdr_type; 190190225Srpaulo 191190225Srpaulo /* basic sanity checks */ 192190225Srpaulo if ( erf == NULL ) 193190225Srpaulo return 0; 194190225Srpaulo if ( len < 16 ) 195190225Srpaulo return 0; 196190225Srpaulo 197190225Srpaulo /* check if we have any extension headers */ 198190225Srpaulo if ( (erf[8] & 0x80) == 0x00 ) 199190225Srpaulo return 0; 200190225Srpaulo 201190225Srpaulo /* loop over the extension headers */ 202190225Srpaulo do { 203190225Srpaulo 204190225Srpaulo /* sanity check we have enough bytes */ 205190225Srpaulo if ( len <= (24 + (hdr_num * 8)) ) 206190225Srpaulo return hdr_num; 207190225Srpaulo 208190225Srpaulo /* get the header type */ 209190225Srpaulo hdr_type = erf[(16 + (hdr_num * 8))]; 210190225Srpaulo hdr_num++; 211190225Srpaulo 212190225Srpaulo } while ( hdr_type & 0x80 ); 213190225Srpaulo 214190225Srpaulo return hdr_num; 215190225Srpaulo} 216190225Srpaulo 217127664Sbms/* 218127664Sbms * Read at most max_packets from the capture stream and call the callback 219127664Sbms * for each of them. Returns the number of packets handled, -1 if an 220127664Sbms * error occured, or -2 if we were told to break out of the loop. 221127664Sbms */ 222146768Ssamstatic int 223146768Ssamdag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 224146768Ssam{ 225127664Sbms unsigned int processed = 0; 226127664Sbms int flags = p->md.dag_offset_flags; 227127664Sbms unsigned int nonblocking = flags & DAGF_NONBLOCK; 228190225Srpaulo unsigned int num_ext_hdr = 0; 229127664Sbms 230162012Ssam /* Get the next bufferful of packets (if necessary). */ 231162012Ssam while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) { 232127664Sbms 233162012Ssam /* 234162012Ssam * Has "pcap_breakloop()" been called? 235162012Ssam */ 236162012Ssam if (p->break_loop) { 237127664Sbms /* 238162012Ssam * Yes - clear the flag that indicates that 239162012Ssam * it has, and return -2 to indicate that 240162012Ssam * we were told to break out of the loop. 241127664Sbms */ 242162012Ssam p->break_loop = 0; 243162012Ssam return -2; 244162012Ssam } 245127664Sbms 246162012Ssam#ifdef HAVE_DAG_STREAMS_API 247162012Ssam /* dag_advance_stream() will block (unless nonblock is called) 248162012Ssam * until 64kB of data has accumulated. 249162012Ssam * If to_ms is set, it will timeout before 64kB has accumulated. 250162012Ssam * We wait for 64kB because processing a few packets at a time 251162012Ssam * can cause problems at high packet rates (>200kpps) due 252162012Ssam * to inefficiencies. 253162012Ssam * This does mean if to_ms is not specified the capture may 'hang' 254162012Ssam * for long periods if the data rate is extremely slow (<64kB/sec) 255162012Ssam * If non-block is specified it will return immediately. The user 256162012Ssam * is then responsible for efficiency. 257162012Ssam */ 258190225Srpaulo if ( NULL == (p->md.dag_mem_top = dag_advance_stream(p->fd, p->md.dag_stream, &(p->md.dag_mem_bottom))) ) { 259190225Srpaulo return -1; 260190225Srpaulo } 261162012Ssam#else 262162012Ssam /* dag_offset does not support timeouts */ 263162012Ssam p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), flags); 264162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 265162012Ssam 266162012Ssam if (nonblocking && (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size)) 267162012Ssam { 268162012Ssam /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ 269162012Ssam return 0; 270127664Sbms } 271162012Ssam 272162012Ssam if(!nonblocking && 273162012Ssam p->md.dag_timeout && 274162012Ssam (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size)) 275162012Ssam { 276162012Ssam /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ 277162012Ssam return 0; 278162012Ssam } 279162012Ssam 280162012Ssam } 281146768Ssam 282162012Ssam /* Process the packets. */ 283162012Ssam while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) { 284190225Srpaulo 285162012Ssam unsigned short packet_len = 0; 286162012Ssam int caplen = 0; 287162012Ssam struct pcap_pkthdr pcap_header; 288190225Srpaulo 289162012Ssam#ifdef HAVE_DAG_STREAMS_API 290162012Ssam dag_record_t *header = (dag_record_t *)(p->md.dag_mem_bottom); 291162012Ssam#else 292162012Ssam dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom); 293162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 294162012Ssam 295190225Srpaulo u_char *dp = ((u_char *)header); /* + dag_record_size; */ 296162012Ssam unsigned short rlen; 297127664Sbms 298162012Ssam /* 299162012Ssam * Has "pcap_breakloop()" been called? 300162012Ssam */ 301162012Ssam if (p->break_loop) { 302127664Sbms /* 303162012Ssam * Yes - clear the flag that indicates that 304162012Ssam * it has, and return -2 to indicate that 305162012Ssam * we were told to break out of the loop. 306127664Sbms */ 307162012Ssam p->break_loop = 0; 308162012Ssam return -2; 309162012Ssam } 310127664Sbms 311162012Ssam rlen = ntohs(header->rlen); 312162012Ssam if (rlen < dag_record_size) 313162012Ssam { 314162012Ssam strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); 315162012Ssam return -1; 316162012Ssam } 317162012Ssam p->md.dag_mem_bottom += rlen; 318162012Ssam 319162012Ssam /* Count lost packets. */ 320190225Srpaulo switch((header->type & 0x7f)) { 321190225Srpaulo /* in these types the color value overwrites the lctr */ 322162012Ssam case TYPE_COLOR_HDLC_POS: 323162012Ssam case TYPE_COLOR_ETH: 324172677Smlaier case TYPE_DSM_COLOR_HDLC_POS: 325172677Smlaier case TYPE_DSM_COLOR_ETH: 326172677Smlaier case TYPE_COLOR_MC_HDLC_POS: 327190225Srpaulo case TYPE_COLOR_HASH_ETH: 328190225Srpaulo case TYPE_COLOR_HASH_POS: 329172677Smlaier break; 330172677Smlaier 331162012Ssam default: 332127664Sbms if (header->lctr) { 333146768Ssam if (p->md.stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { 334127664Sbms p->md.stat.ps_drop = UINT_MAX; 335127664Sbms } else { 336146768Ssam p->md.stat.ps_drop += ntohs(header->lctr); 337127664Sbms } 338127664Sbms } 339162012Ssam } 340190225Srpaulo 341190225Srpaulo if ((header->type & 0x7f) == TYPE_PAD) { 342190225Srpaulo continue; 343190225Srpaulo } 344127664Sbms 345190225Srpaulo num_ext_hdr = dag_erf_ext_header_count(dp, rlen); 346190225Srpaulo 347190225Srpaulo /* ERF encapsulation */ 348190225Srpaulo /* The Extensible Record Format is not dropped for this kind of encapsulation, 349190225Srpaulo * and will be handled as a pseudo header by the decoding application. 350190225Srpaulo * The information carried in the ERF header and in the optional subheader (if present) 351190225Srpaulo * could be merged with the libpcap information, to offer a better decoding. 352190225Srpaulo * The packet length is 353190225Srpaulo * o the length of the packet on the link (header->wlen), 354190225Srpaulo * o plus the length of the ERF header (dag_record_size), as the length of the 355190225Srpaulo * pseudo header will be adjusted during the decoding, 356190225Srpaulo * o plus the length of the optional subheader (if present). 357190225Srpaulo * 358190225Srpaulo * The capture length is header.rlen and the byte stuffing for alignment will be dropped 359190225Srpaulo * if the capture length is greater than the packet length. 360190225Srpaulo */ 361190225Srpaulo if (p->linktype == DLT_ERF) { 362190225Srpaulo packet_len = ntohs(header->wlen) + dag_record_size; 363190225Srpaulo caplen = rlen; 364190225Srpaulo switch ((header->type & 0x7f)) { 365190225Srpaulo case TYPE_MC_AAL5: 366190225Srpaulo case TYPE_MC_ATM: 367190225Srpaulo case TYPE_MC_HDLC: 368214518Srpaulo case TYPE_MC_RAW_CHANNEL: 369214518Srpaulo case TYPE_MC_RAW: 370214518Srpaulo case TYPE_MC_AAL2: 371214518Srpaulo case TYPE_COLOR_MC_HDLC_POS: 372190225Srpaulo packet_len += 4; /* MC header */ 373190225Srpaulo break; 374190225Srpaulo 375190225Srpaulo case TYPE_COLOR_HASH_ETH: 376190225Srpaulo case TYPE_DSM_COLOR_ETH: 377190225Srpaulo case TYPE_COLOR_ETH: 378190225Srpaulo case TYPE_ETH: 379190225Srpaulo packet_len += 2; /* ETH header */ 380190225Srpaulo break; 381190225Srpaulo } /* switch type */ 382190225Srpaulo 383190225Srpaulo /* Include ERF extension headers */ 384190225Srpaulo packet_len += (8 * num_ext_hdr); 385190225Srpaulo 386190225Srpaulo if (caplen > packet_len) { 387190225Srpaulo caplen = packet_len; 388190225Srpaulo } 389190225Srpaulo } else { 390190225Srpaulo /* Other kind of encapsulation according to the header Type */ 391190225Srpaulo 392190225Srpaulo /* Skip over generic ERF header */ 393190225Srpaulo dp += dag_record_size; 394190225Srpaulo /* Skip over extension headers */ 395190225Srpaulo dp += 8 * num_ext_hdr; 396190225Srpaulo 397190225Srpaulo switch((header->type & 0x7f)) { 398190225Srpaulo case TYPE_ATM: 399190225Srpaulo case TYPE_AAL5: 400190225Srpaulo if (header->type == TYPE_AAL5) { 401190225Srpaulo packet_len = ntohs(header->wlen); 402190225Srpaulo caplen = rlen - dag_record_size; 403190225Srpaulo } 404190225Srpaulo case TYPE_MC_ATM: 405190225Srpaulo if (header->type == TYPE_MC_ATM) { 406190225Srpaulo caplen = packet_len = ATM_CELL_SIZE; 407190225Srpaulo dp+=4; 408190225Srpaulo } 409190225Srpaulo case TYPE_MC_AAL5: 410190225Srpaulo if (header->type == TYPE_MC_AAL5) { 411190225Srpaulo packet_len = ntohs(header->wlen); 412190225Srpaulo caplen = rlen - dag_record_size - 4; 413190225Srpaulo dp+=4; 414190225Srpaulo } 415190225Srpaulo if (header->type == TYPE_ATM) { 416190225Srpaulo caplen = packet_len = ATM_CELL_SIZE; 417190225Srpaulo } 418190225Srpaulo if (p->linktype == DLT_SUNATM) { 419190225Srpaulo struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; 420190225Srpaulo unsigned long rawatm; 421190225Srpaulo 422190225Srpaulo rawatm = ntohl(*((unsigned long *)dp)); 423190225Srpaulo sunatm->vci = htons((rawatm >> 4) & 0xffff); 424190225Srpaulo sunatm->vpi = (rawatm >> 20) & 0x00ff; 425190225Srpaulo sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | 426190225Srpaulo ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : 427190225Srpaulo ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : 428190225Srpaulo ((dp[ATM_HDR_SIZE] == 0xaa && 429190225Srpaulo dp[ATM_HDR_SIZE+1] == 0xaa && 430190225Srpaulo dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); 431190225Srpaulo 432190225Srpaulo } else { 433190225Srpaulo packet_len -= ATM_HDR_SIZE; 434190225Srpaulo caplen -= ATM_HDR_SIZE; 435190225Srpaulo dp += ATM_HDR_SIZE; 436190225Srpaulo } 437190225Srpaulo break; 438190225Srpaulo 439190225Srpaulo case TYPE_COLOR_HASH_ETH: 440190225Srpaulo case TYPE_DSM_COLOR_ETH: 441190225Srpaulo case TYPE_COLOR_ETH: 442190225Srpaulo case TYPE_ETH: 443190225Srpaulo packet_len = ntohs(header->wlen); 444190225Srpaulo packet_len -= (p->md.dag_fcs_bits >> 3); 445190225Srpaulo caplen = rlen - dag_record_size - 2; 446190225Srpaulo if (caplen > packet_len) { 447190225Srpaulo caplen = packet_len; 448190225Srpaulo } 449190225Srpaulo dp += 2; 450190225Srpaulo break; 451190225Srpaulo 452190225Srpaulo case TYPE_COLOR_HASH_POS: 453190225Srpaulo case TYPE_DSM_COLOR_HDLC_POS: 454190225Srpaulo case TYPE_COLOR_HDLC_POS: 455190225Srpaulo case TYPE_HDLC_POS: 456190225Srpaulo packet_len = ntohs(header->wlen); 457190225Srpaulo packet_len -= (p->md.dag_fcs_bits >> 3); 458190225Srpaulo caplen = rlen - dag_record_size; 459190225Srpaulo if (caplen > packet_len) { 460190225Srpaulo caplen = packet_len; 461190225Srpaulo } 462190225Srpaulo break; 463190225Srpaulo 464190225Srpaulo case TYPE_COLOR_MC_HDLC_POS: 465190225Srpaulo case TYPE_MC_HDLC: 466190225Srpaulo packet_len = ntohs(header->wlen); 467190225Srpaulo packet_len -= (p->md.dag_fcs_bits >> 3); 468190225Srpaulo caplen = rlen - dag_record_size - 4; 469190225Srpaulo if (caplen > packet_len) { 470190225Srpaulo caplen = packet_len; 471190225Srpaulo } 472190225Srpaulo /* jump the MC_HDLC_HEADER */ 473190225Srpaulo dp += 4; 474190225Srpaulo#ifdef DLT_MTP2_WITH_PHDR 475190225Srpaulo if (p->linktype == DLT_MTP2_WITH_PHDR) { 476190225Srpaulo /* Add the MTP2 Pseudo Header */ 477190225Srpaulo caplen += MTP2_HDR_LEN; 478190225Srpaulo packet_len += MTP2_HDR_LEN; 479190225Srpaulo 480190225Srpaulo TempPkt[MTP2_SENT_OFFSET] = 0; 481190225Srpaulo TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN; 482190225Srpaulo *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01); 483190225Srpaulo *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff); 484190225Srpaulo memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen); 485190225Srpaulo dp = TempPkt; 486190225Srpaulo } 487190225Srpaulo#endif 488190225Srpaulo break; 489190225Srpaulo 490190225Srpaulo case TYPE_IPV4: 491214518Srpaulo case TYPE_IPV6: 492190225Srpaulo packet_len = ntohs(header->wlen); 493190225Srpaulo caplen = rlen - dag_record_size; 494190225Srpaulo if (caplen > packet_len) { 495190225Srpaulo caplen = packet_len; 496190225Srpaulo } 497190225Srpaulo break; 498190225Srpaulo 499214518Srpaulo /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */ 500214518Srpaulo case TYPE_MC_RAW: 501214518Srpaulo case TYPE_MC_RAW_CHANNEL: 502214518Srpaulo case TYPE_IP_COUNTER: 503214518Srpaulo case TYPE_TCP_FLOW_COUNTER: 504214518Srpaulo case TYPE_INFINIBAND: 505214518Srpaulo case TYPE_RAW_LINK: 506214518Srpaulo case TYPE_INFINIBAND_LINK: 507190225Srpaulo default: 508190225Srpaulo /* Unhandled ERF type. 509190225Srpaulo * Ignore rather than generating error 510190225Srpaulo */ 511190225Srpaulo continue; 512190225Srpaulo } /* switch type */ 513190225Srpaulo 514190225Srpaulo /* Skip over extension headers */ 515190225Srpaulo caplen -= (8 * num_ext_hdr); 516190225Srpaulo 517190225Srpaulo } /* ERF encapsulation */ 518190225Srpaulo 519190225Srpaulo if (caplen > p->snapshot) 520190225Srpaulo caplen = p->snapshot; 521190225Srpaulo 522162012Ssam /* Run the packet filter if there is one. */ 523162012Ssam if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { 524190225Srpaulo 525162012Ssam /* convert between timestamp formats */ 526162012Ssam register unsigned long long ts; 527127664Sbms 528162012Ssam if (IS_BIGENDIAN()) { 529172677Smlaier ts = SWAPLL(header->ts); 530162012Ssam } else { 531162012Ssam ts = header->ts; 532162012Ssam } 533127664Sbms 534162012Ssam pcap_header.ts.tv_sec = ts >> 32; 535162012Ssam ts = (ts & 0xffffffffULL) * 1000000; 536162012Ssam ts += 0x80000000; /* rounding */ 537162012Ssam pcap_header.ts.tv_usec = ts >> 32; 538162012Ssam if (pcap_header.ts.tv_usec >= 1000000) { 539162012Ssam pcap_header.ts.tv_usec -= 1000000; 540162012Ssam pcap_header.ts.tv_sec++; 541162012Ssam } 542127664Sbms 543162012Ssam /* Fill in our own header data */ 544162012Ssam pcap_header.caplen = caplen; 545162012Ssam pcap_header.len = packet_len; 546146768Ssam 547162012Ssam /* Count the packet. */ 548162012Ssam p->md.stat.ps_recv++; 549146768Ssam 550162012Ssam /* Call the user supplied callback function */ 551162012Ssam callback(user, &pcap_header, dp); 552146768Ssam 553162012Ssam /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ 554162012Ssam processed++; 555190225Srpaulo if (processed == cnt && cnt > 0) 556162012Ssam { 557162012Ssam /* Reached the user-specified limit. */ 558162012Ssam return cnt; 559127664Sbms } 560127664Sbms } 561162012Ssam } 562127664Sbms 563127664Sbms return processed; 564127664Sbms} 565127664Sbms 566146768Ssamstatic int 567146768Ssamdag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 568146768Ssam{ 569146768Ssam strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", 570146768Ssam PCAP_ERRBUF_SIZE); 571146768Ssam return (-1); 572146768Ssam} 573146768Ssam 574127664Sbms/* 575127664Sbms * Get a handle for a live capture from the given DAG device. Passing a NULL 576127664Sbms * device will result in a failure. The promisc flag is ignored because DAG 577190225Srpaulo * cards are always promiscuous. The to_ms parameter is used in setting the 578190225Srpaulo * API polling parameters. 579127664Sbms * 580172677Smlaier * snaplen is now also ignored, until we get per-stream slen support. Set 581190225Srpaulo * slen with approprite DAG tool BEFORE pcap_activate(). 582172677Smlaier * 583127664Sbms * See also pcap(3). 584127664Sbms */ 585190225Srpaulostatic int dag_activate(pcap_t* handle) 586146768Ssam{ 587190225Srpaulo#if 0 588146768Ssam char conf[30]; /* dag configure string */ 589190225Srpaulo#endif 590146768Ssam char *s; 591146768Ssam int n; 592146768Ssam daginf_t* daginf; 593172677Smlaier char * newDev = NULL; 594190225Srpaulo char * device = handle->opt.source; 595162012Ssam#ifdef HAVE_DAG_STREAMS_API 596162012Ssam uint32_t mindata; 597162012Ssam struct timeval maxwait; 598162012Ssam struct timeval poll; 599162012Ssam#endif 600162012Ssam 601146768Ssam if (device == NULL) { 602190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); 603190225Srpaulo return -1; 604146768Ssam } 605127664Sbms 606146768Ssam /* Initialize some components of the pcap structure. */ 607127664Sbms 608172677Smlaier#ifdef HAVE_DAG_STREAMS_API 609162012Ssam newDev = (char *)malloc(strlen(device) + 16); 610172677Smlaier if (newDev == NULL) { 611190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); 612172677Smlaier goto fail; 613172677Smlaier } 614162012Ssam 615162012Ssam /* Parse input name to get dag device and stream number if provided */ 616162012Ssam if (dag_parse_name(device, newDev, strlen(device) + 16, &handle->md.dag_stream) < 0) { 617190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: %s\n", pcap_strerror(errno)); 618162012Ssam goto fail; 619162012Ssam } 620162012Ssam device = newDev; 621162012Ssam 622162012Ssam if (handle->md.dag_stream%2) { 623190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture\n"); 624162012Ssam goto fail; 625162012Ssam } 626162012Ssam#else 627172677Smlaier if (strncmp(device, "/dev/", 5) != 0) { 628172677Smlaier newDev = (char *)malloc(strlen(device) + 5); 629172677Smlaier if (newDev == NULL) { 630190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); 631172677Smlaier goto fail; 632172677Smlaier } 633172677Smlaier strcpy(newDev, "/dev/"); 634172677Smlaier strcat(newDev, device); 635146768Ssam device = newDev; 636146768Ssam } 637162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 638127664Sbms 639146768Ssam /* setup device parameters */ 640146768Ssam if((handle->fd = dag_open((char *)device)) < 0) { 641190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno)); 642146768Ssam goto fail; 643146768Ssam } 644127664Sbms 645162012Ssam#ifdef HAVE_DAG_STREAMS_API 646162012Ssam /* Open requested stream. Can fail if already locked or on error */ 647162012Ssam if (dag_attach_stream(handle->fd, handle->md.dag_stream, 0, 0) < 0) { 648190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s\n", pcap_strerror(errno)); 649172677Smlaier goto failclose; 650162012Ssam } 651162012Ssam 652162012Ssam /* Set up default poll parameters for stream 653162012Ssam * Can be overridden by pcap_set_nonblock() 654162012Ssam */ 655162012Ssam if (dag_get_stream_poll(handle->fd, handle->md.dag_stream, 656162012Ssam &mindata, &maxwait, &poll) < 0) { 657190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); 658172677Smlaier goto faildetach; 659162012Ssam } 660162012Ssam 661162012Ssam /* Amount of data to collect in Bytes before calling callbacks. 662162012Ssam * Important for efficiency, but can introduce latency 663162012Ssam * at low packet rates if to_ms not set! 664162012Ssam */ 665162012Ssam mindata = 65536; 666162012Ssam 667190225Srpaulo /* Obey md.timeout (was to_ms) if supplied. This is a good idea! 668162012Ssam * Recommend 10-100ms. Calls will time out even if no data arrived. 669162012Ssam */ 670190225Srpaulo maxwait.tv_sec = handle->md.timeout/1000; 671190225Srpaulo maxwait.tv_usec = (handle->md.timeout%1000) * 1000; 672162012Ssam 673162012Ssam if (dag_set_stream_poll(handle->fd, handle->md.dag_stream, 674162012Ssam mindata, &maxwait, &poll) < 0) { 675190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); 676172677Smlaier goto faildetach; 677162012Ssam } 678162012Ssam 679162012Ssam#else 680162012Ssam if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { 681190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno)); 682172677Smlaier goto failclose; 683162012Ssam } 684162012Ssam 685162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 686162012Ssam 687172677Smlaier /* XXX Not calling dag_configure() to set slen; this is unsafe in 688172677Smlaier * multi-stream environments as the gpp config is global. 689172677Smlaier * Once the firmware provides 'per-stream slen' this can be supported 690172677Smlaier * again via the Config API without side-effects */ 691172677Smlaier#if 0 692146768Ssam /* set the card snap length to the specified snaplen parameter */ 693172677Smlaier /* This is a really bad idea, as different cards have different 694172677Smlaier * valid slen ranges. Should fix in Config API. */ 695190225Srpaulo if (handle->snapshot == 0 || handle->snapshot > MAX_DAG_SNAPLEN) { 696190225Srpaulo handle->snapshot = MAX_DAG_SNAPLEN; 697146768Ssam } else if (snaplen < MIN_DAG_SNAPLEN) { 698190225Srpaulo handle->snapshot = MIN_DAG_SNAPLEN; 699146768Ssam } 700146768Ssam /* snap len has to be a multiple of 4 */ 701146768Ssam snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); 702127664Sbms 703146768Ssam if(dag_configure(handle->fd, conf) < 0) { 704190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno)); 705172677Smlaier goto faildetach; 706146768Ssam } 707172677Smlaier#endif 708172677Smlaier 709162012Ssam#ifdef HAVE_DAG_STREAMS_API 710162012Ssam if(dag_start_stream(handle->fd, handle->md.dag_stream) < 0) { 711190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s\n", device, pcap_strerror(errno)); 712172677Smlaier goto faildetach; 713146768Ssam } 714162012Ssam#else 715146768Ssam if(dag_start(handle->fd) < 0) { 716190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno)); 717172677Smlaier goto failclose; 718146768Ssam } 719162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 720127664Sbms 721146768Ssam /* 722146768Ssam * Important! You have to ensure bottom is properly 723146768Ssam * initialized to zero on startup, it won't give you 724146768Ssam * a compiler warning if you make this mistake! 725146768Ssam */ 726146768Ssam handle->md.dag_mem_bottom = 0; 727146768Ssam handle->md.dag_mem_top = 0; 728127664Sbms 729190225Srpaulo /* 730190225Srpaulo * Find out how many FCS bits we should strip. 731190225Srpaulo * First, query the card to see if it strips the FCS. 732190225Srpaulo */ 733146768Ssam daginf = dag_info(handle->fd); 734190225Srpaulo if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) { 735146768Ssam /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ 736146768Ssam handle->md.dag_fcs_bits = 0; 737127664Sbms 738190225Srpaulo /* Note that no FCS will be supplied. */ 739190225Srpaulo handle->linktype_ext = LT_FCS_DATALINK_EXT(0); 740190225Srpaulo } else { 741190225Srpaulo /* 742190225Srpaulo * Start out assuming it's 32 bits. 743190225Srpaulo */ 744190225Srpaulo handle->md.dag_fcs_bits = 32; 745190225Srpaulo 746190225Srpaulo /* Allow an environment variable to override. */ 747190225Srpaulo if ((s = getenv("ERF_FCS_BITS")) != NULL) { 748190225Srpaulo if ((n = atoi(s)) == 0 || n == 16 || n == 32) { 749190225Srpaulo handle->md.dag_fcs_bits = n; 750190225Srpaulo } else { 751190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 752190225Srpaulo "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n); 753190225Srpaulo goto failstop; 754190225Srpaulo } 755146768Ssam } 756190225Srpaulo 757190225Srpaulo /* 758190225Srpaulo * Did the user request that they not be stripped? 759190225Srpaulo */ 760190225Srpaulo if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) { 761190225Srpaulo /* Yes. Note the number of bytes that will be 762190225Srpaulo supplied. */ 763190225Srpaulo handle->linktype_ext = LT_FCS_DATALINK_EXT(handle->md.dag_fcs_bits/16); 764190225Srpaulo 765190225Srpaulo /* And don't strip them. */ 766190225Srpaulo handle->md.dag_fcs_bits = 0; 767190225Srpaulo } 768146768Ssam } 769127664Sbms 770190225Srpaulo handle->md.dag_timeout = handle->md.timeout; 771127664Sbms 772146768Ssam handle->linktype = -1; 773190225Srpaulo if (dag_get_datalink(handle) < 0) 774172677Smlaier goto failstop; 775146768Ssam 776146768Ssam handle->bufsize = 0; 777127664Sbms 778146768Ssam if (new_pcap_dag(handle) < 0) { 779190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno)); 780172677Smlaier goto failstop; 781146768Ssam } 782127664Sbms 783146768Ssam /* 784162012Ssam * "select()" and "poll()" don't work on DAG device descriptors. 785146768Ssam */ 786146768Ssam handle->selectable_fd = -1; 787146768Ssam 788172677Smlaier if (newDev != NULL) { 789172677Smlaier free((char *)newDev); 790172677Smlaier } 791127664Sbms 792146768Ssam handle->read_op = dag_read; 793146768Ssam handle->inject_op = dag_inject; 794146768Ssam handle->setfilter_op = dag_setfilter; 795147894Ssam handle->setdirection_op = NULL; /* Not implemented.*/ 796146768Ssam handle->set_datalink_op = dag_set_datalink; 797146768Ssam handle->getnonblock_op = pcap_getnonblock_fd; 798146768Ssam handle->setnonblock_op = dag_setnonblock; 799146768Ssam handle->stats_op = dag_stats; 800190225Srpaulo handle->cleanup_op = dag_platform_cleanup; 801172677Smlaier handle->md.stat.ps_drop = 0; 802172677Smlaier handle->md.stat.ps_recv = 0; 803214518Srpaulo handle->md.stat.ps_ifdrop = 0; 804190225Srpaulo return 0; 805127664Sbms 806172677Smlaier#ifdef HAVE_DAG_STREAMS_API 807172677Smlaierfailstop: 808190225Srpaulo if (dag_stop_stream(handle->fd, handle->md.dag_stream) < 0) { 809190225Srpaulo fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); 810172677Smlaier } 811172677Smlaier 812172677Smlaierfaildetach: 813190225Srpaulo if (dag_detach_stream(handle->fd, handle->md.dag_stream) < 0) 814190225Srpaulo fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); 815190225Srpaulo#else 816172677Smlaierfailstop: 817190225Srpaulo if (dag_stop(handle->fd) < 0) 818190225Srpaulo fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 819172677Smlaier#endif /* HAVE_DAG_STREAMS_API */ 820172677Smlaier 821172677Smlaierfailclose: 822190225Srpaulo if (dag_close(handle->fd) < 0) 823190225Srpaulo fprintf(stderr,"dag_close: %s\n", strerror(errno)); 824190225Srpaulo delete_pcap_dag(handle); 825190225Srpaulo 826127664Sbmsfail: 827190225Srpaulo pcap_cleanup_live_common(handle); 828162012Ssam if (newDev != NULL) { 829162012Ssam free((char *)newDev); 830146768Ssam } 831127664Sbms 832190225Srpaulo return PCAP_ERROR; 833127664Sbms} 834127664Sbms 835252281Sdelphijpcap_t *dag_create(const char *device, char *ebuf, int *is_ours) 836190225Srpaulo{ 837252281Sdelphij const char *cp; 838252281Sdelphij char *cpend; 839252281Sdelphij long devnum; 840190225Srpaulo pcap_t *p; 841190225Srpaulo 842252281Sdelphij /* Does this look like a DAG device? */ 843252281Sdelphij cp = strrchr(device, '/'); 844252281Sdelphij if (cp == NULL) 845252281Sdelphij cp = device; 846252281Sdelphij /* Does it begin with "dag"? */ 847252281Sdelphij if (strncmp(cp, "dag", 3) != 0) { 848252281Sdelphij /* Nope, doesn't begin with "dag" */ 849252281Sdelphij *is_ours = 0; 850252281Sdelphij return NULL; 851252281Sdelphij } 852252281Sdelphij /* Yes - is "dag" followed by a number from 0 to MAXDAG? */ 853252281Sdelphij cp += 3; 854252281Sdelphij devnum = strtol(cp, &cpend, 10); 855252281Sdelphij if (cpend == cp || *cpend != '\0') { 856252281Sdelphij /* Not followed by a number. */ 857252281Sdelphij *is_ours = 0; 858252281Sdelphij return NULL; 859252281Sdelphij } 860252281Sdelphij if (devnum < 0 || devnum > MAXDAG) { 861252281Sdelphij /* Followed by a non-valid number. */ 862252281Sdelphij *is_ours = 0; 863252281Sdelphij return NULL; 864252281Sdelphij } 865252281Sdelphij 866252281Sdelphij /* OK, it's probably ours. */ 867252281Sdelphij *is_ours = 1; 868252281Sdelphij 869190225Srpaulo p = pcap_create_common(device, ebuf); 870190225Srpaulo if (p == NULL) 871190225Srpaulo return NULL; 872190225Srpaulo 873190225Srpaulo p->activate_op = dag_activate; 874190225Srpaulo return p; 875190225Srpaulo} 876190225Srpaulo 877146768Ssamstatic int 878146768Ssamdag_stats(pcap_t *p, struct pcap_stat *ps) { 879146768Ssam /* This needs to be filled out correctly. Hopefully a dagapi call will 880146768Ssam provide all necessary information. 881146768Ssam */ 882146768Ssam /*p->md.stat.ps_recv = 0;*/ 883146768Ssam /*p->md.stat.ps_drop = 0;*/ 884146768Ssam 885146768Ssam *ps = p->md.stat; 886127664Sbms 887146768Ssam return 0; 888127664Sbms} 889127664Sbms 890127664Sbms/* 891190225Srpaulo * Previously we just generated a list of all possible names and let 892190225Srpaulo * pcap_add_if() attempt to open each one, but with streams this adds up 893190225Srpaulo * to 81 possibilities which is inefficient. 894190225Srpaulo * 895190225Srpaulo * Since we know more about the devices we can prune the tree here. 896190225Srpaulo * pcap_add_if() will still retest each device but the total number of 897190225Srpaulo * open attempts will still be much less than the naive approach. 898127664Sbms */ 899127664Sbmsint 900252281Sdelphijdag_findalldevs(pcap_if_t **devlistp, char *errbuf) 901127664Sbms{ 902162012Ssam char name[12]; /* XXX - pick a size */ 903146768Ssam int ret = 0; 904162012Ssam int c; 905190225Srpaulo char dagname[DAGNAME_BUFSIZE]; 906190225Srpaulo int dagstream; 907190225Srpaulo int dagfd; 908127664Sbms 909252281Sdelphij /* Try all the DAGs 0-MAXDAG */ 910252281Sdelphij for (c = 0; c <= MAXDAG; c++) { 911162012Ssam snprintf(name, 12, "dag%d", c); 912190225Srpaulo if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream)) 913190225Srpaulo { 914190225Srpaulo return -1; 915146768Ssam } 916190225Srpaulo if ( (dagfd = dag_open(dagname)) >= 0 ) { 917190225Srpaulo if (pcap_add_if(devlistp, name, 0, NULL, errbuf) == -1) { 918190225Srpaulo /* 919190225Srpaulo * Failure. 920190225Srpaulo */ 921190225Srpaulo ret = -1; 922190225Srpaulo } 923162012Ssam#ifdef HAVE_DAG_STREAMS_API 924190225Srpaulo { 925190225Srpaulo int stream, rxstreams; 926190225Srpaulo rxstreams = dag_rx_get_stream_count(dagfd); 927236167Sdelphij for(stream=0;stream<DAG_STREAM_MAX;stream+=2) { 928190225Srpaulo if (0 == dag_attach_stream(dagfd, stream, 0, 0)) { 929190225Srpaulo dag_detach_stream(dagfd, stream); 930190225Srpaulo 931190225Srpaulo snprintf(name, 10, "dag%d:%d", c, stream); 932190225Srpaulo if (pcap_add_if(devlistp, name, 0, NULL, errbuf) == -1) { 933190225Srpaulo /* 934190225Srpaulo * Failure. 935190225Srpaulo */ 936190225Srpaulo ret = -1; 937190225Srpaulo } 938236167Sdelphij 939236167Sdelphij rxstreams--; 940236167Sdelphij if(rxstreams <= 0) { 941236167Sdelphij break; 942236167Sdelphij } 943190225Srpaulo } 944190225Srpaulo } 945190225Srpaulo } 946190225Srpaulo#endif /* HAVE_DAG_STREAMS_API */ 947190225Srpaulo dag_close(dagfd); 948146768Ssam } 949190225Srpaulo 950146768Ssam } 951146768Ssam return (ret); 952127664Sbms} 953127664Sbms 954127664Sbms/* 955127664Sbms * Installs the given bpf filter program in the given pcap structure. There is 956127664Sbms * no attempt to store the filter in kernel memory as that is not supported 957127664Sbms * with DAG cards. 958127664Sbms */ 959146768Ssamstatic int 960146768Ssamdag_setfilter(pcap_t *p, struct bpf_program *fp) 961146768Ssam{ 962146768Ssam if (!p) 963146768Ssam return -1; 964146768Ssam if (!fp) { 965146768Ssam strncpy(p->errbuf, "setfilter: No filter specified", 966146768Ssam sizeof(p->errbuf)); 967146768Ssam return -1; 968146768Ssam } 969127664Sbms 970146768Ssam /* Make our private copy of the filter */ 971127664Sbms 972146768Ssam if (install_bpf_program(p, fp) < 0) 973146768Ssam return -1; 974127664Sbms 975146768Ssam p->md.use_bpf = 0; 976127664Sbms 977146768Ssam return (0); 978127664Sbms} 979127664Sbms 980127664Sbmsstatic int 981127664Sbmsdag_set_datalink(pcap_t *p, int dlt) 982127664Sbms{ 983146768Ssam p->linktype = dlt; 984146768Ssam 985127664Sbms return (0); 986127664Sbms} 987127664Sbms 988127664Sbmsstatic int 989127664Sbmsdag_setnonblock(pcap_t *p, int nonblock, char *errbuf) 990127664Sbms{ 991127664Sbms /* 992127664Sbms * Set non-blocking mode on the FD. 993127664Sbms * XXX - is that necessary? If not, don't bother calling it, 994127664Sbms * and have a "dag_getnonblock()" function that looks at 995127664Sbms * "p->md.dag_offset_flags". 996127664Sbms */ 997127664Sbms if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0) 998127664Sbms return (-1); 999162012Ssam#ifdef HAVE_DAG_STREAMS_API 1000162012Ssam { 1001162012Ssam uint32_t mindata; 1002162012Ssam struct timeval maxwait; 1003162012Ssam struct timeval poll; 1004162012Ssam 1005162012Ssam if (dag_get_stream_poll(p->fd, p->md.dag_stream, 1006162012Ssam &mindata, &maxwait, &poll) < 0) { 1007162012Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); 1008162012Ssam return -1; 1009162012Ssam } 1010162012Ssam 1011162012Ssam /* Amount of data to collect in Bytes before calling callbacks. 1012162012Ssam * Important for efficiency, but can introduce latency 1013162012Ssam * at low packet rates if to_ms not set! 1014162012Ssam */ 1015162012Ssam if(nonblock) 1016162012Ssam mindata = 0; 1017162012Ssam else 1018162012Ssam mindata = 65536; 1019162012Ssam 1020162012Ssam if (dag_set_stream_poll(p->fd, p->md.dag_stream, 1021162012Ssam mindata, &maxwait, &poll) < 0) { 1022162012Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); 1023162012Ssam return -1; 1024162012Ssam } 1025162012Ssam } 1026162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 1027127664Sbms if (nonblock) { 1028127664Sbms p->md.dag_offset_flags |= DAGF_NONBLOCK; 1029127664Sbms } else { 1030127664Sbms p->md.dag_offset_flags &= ~DAGF_NONBLOCK; 1031127664Sbms } 1032127664Sbms return (0); 1033127664Sbms} 1034127664Sbms 1035127664Sbmsstatic int 1036127664Sbmsdag_get_datalink(pcap_t *p) 1037127664Sbms{ 1038190225Srpaulo int index=0, dlt_index=0; 1039172677Smlaier uint8_t types[255]; 1040127664Sbms 1041172677Smlaier memset(types, 0, 255); 1042172677Smlaier 1043172677Smlaier if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) { 1044146768Ssam (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); 1045146768Ssam return (-1); 1046146768Ssam } 1047127664Sbms 1048172677Smlaier p->linktype = 0; 1049172677Smlaier 1050190225Srpaulo#ifdef HAVE_DAG_GET_STREAM_ERF_TYPES 1051172677Smlaier /* Get list of possible ERF types for this card */ 1052190225Srpaulo if (dag_get_stream_erf_types(p->fd, p->md.dag_stream, types, 255) < 0) { 1053190225Srpaulo snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_stream_erf_types: %s", pcap_strerror(errno)); 1054190225Srpaulo return (-1); 1055190225Srpaulo } 1056190225Srpaulo 1057190225Srpaulo while (types[index]) { 1058190225Srpaulo 1059190225Srpaulo#elif defined HAVE_DAG_GET_ERF_TYPES 1060190225Srpaulo /* Get list of possible ERF types for this card */ 1061172677Smlaier if (dag_get_erf_types(p->fd, types, 255) < 0) { 1062172677Smlaier snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_erf_types: %s", pcap_strerror(errno)); 1063172677Smlaier return (-1); 1064172677Smlaier } 1065172677Smlaier 1066172677Smlaier while (types[index]) { 1067172677Smlaier#else 1068146768Ssam /* Check the type through a dagapi call. */ 1069172677Smlaier types[index] = dag_linktype(p->fd); 1070127664Sbms 1071172677Smlaier { 1072172677Smlaier#endif 1073190225Srpaulo switch((types[index] & 0x7f)) { 1074127664Sbms 1075172677Smlaier case TYPE_HDLC_POS: 1076172677Smlaier case TYPE_COLOR_HDLC_POS: 1077172677Smlaier case TYPE_DSM_COLOR_HDLC_POS: 1078190225Srpaulo case TYPE_COLOR_HASH_POS: 1079190225Srpaulo 1080172677Smlaier if (p->dlt_list != NULL) { 1081190225Srpaulo p->dlt_list[dlt_index++] = DLT_CHDLC; 1082190225Srpaulo p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; 1083190225Srpaulo p->dlt_list[dlt_index++] = DLT_FRELAY; 1084172677Smlaier } 1085172677Smlaier if(!p->linktype) 1086172677Smlaier p->linktype = DLT_CHDLC; 1087172677Smlaier break; 1088146768Ssam 1089172677Smlaier case TYPE_ETH: 1090172677Smlaier case TYPE_COLOR_ETH: 1091172677Smlaier case TYPE_DSM_COLOR_ETH: 1092190225Srpaulo case TYPE_COLOR_HASH_ETH: 1093172677Smlaier /* 1094172677Smlaier * This is (presumably) a real Ethernet capture; give it a 1095172677Smlaier * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 1096172677Smlaier * that an application can let you choose it, in case you're 1097172677Smlaier * capturing DOCSIS traffic that a Cisco Cable Modem 1098172677Smlaier * Termination System is putting out onto an Ethernet (it 1099172677Smlaier * doesn't put an Ethernet header onto the wire, it puts raw 1100172677Smlaier * DOCSIS frames out on the wire inside the low-level 1101172677Smlaier * Ethernet framing). 1102172677Smlaier */ 1103172677Smlaier if (p->dlt_list != NULL) { 1104190225Srpaulo p->dlt_list[dlt_index++] = DLT_EN10MB; 1105190225Srpaulo p->dlt_list[dlt_index++] = DLT_DOCSIS; 1106172677Smlaier } 1107172677Smlaier if(!p->linktype) 1108172677Smlaier p->linktype = DLT_EN10MB; 1109172677Smlaier break; 1110146768Ssam 1111172677Smlaier case TYPE_ATM: 1112172677Smlaier case TYPE_AAL5: 1113172677Smlaier case TYPE_MC_ATM: 1114172677Smlaier case TYPE_MC_AAL5: 1115172677Smlaier if (p->dlt_list != NULL) { 1116190225Srpaulo p->dlt_list[dlt_index++] = DLT_ATM_RFC1483; 1117190225Srpaulo p->dlt_list[dlt_index++] = DLT_SUNATM; 1118172677Smlaier } 1119172677Smlaier if(!p->linktype) 1120172677Smlaier p->linktype = DLT_ATM_RFC1483; 1121172677Smlaier break; 1122146768Ssam 1123172677Smlaier case TYPE_COLOR_MC_HDLC_POS: 1124172677Smlaier case TYPE_MC_HDLC: 1125172677Smlaier if (p->dlt_list != NULL) { 1126190225Srpaulo p->dlt_list[dlt_index++] = DLT_CHDLC; 1127190225Srpaulo p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; 1128190225Srpaulo p->dlt_list[dlt_index++] = DLT_FRELAY; 1129190225Srpaulo p->dlt_list[dlt_index++] = DLT_MTP2; 1130190225Srpaulo p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR; 1131190225Srpaulo p->dlt_list[dlt_index++] = DLT_LAPD; 1132172677Smlaier } 1133172677Smlaier if(!p->linktype) 1134172677Smlaier p->linktype = DLT_CHDLC; 1135172677Smlaier break; 1136146768Ssam 1137190225Srpaulo case TYPE_IPV4: 1138214518Srpaulo case TYPE_IPV6: 1139172677Smlaier if(!p->linktype) 1140190225Srpaulo p->linktype = DLT_RAW; 1141172677Smlaier break; 1142146768Ssam 1143190225Srpaulo case TYPE_LEGACY: 1144190225Srpaulo case TYPE_MC_RAW: 1145190225Srpaulo case TYPE_MC_RAW_CHANNEL: 1146190225Srpaulo case TYPE_IP_COUNTER: 1147190225Srpaulo case TYPE_TCP_FLOW_COUNTER: 1148190225Srpaulo case TYPE_INFINIBAND: 1149214518Srpaulo case TYPE_RAW_LINK: 1150214518Srpaulo case TYPE_INFINIBAND_LINK: 1151172677Smlaier default: 1152190225Srpaulo /* Libpcap cannot deal with these types yet */ 1153214518Srpaulo /* Add no 'native' DLTs, but still covered by DLT_ERF */ 1154190225Srpaulo break; 1155146768Ssam 1156172677Smlaier } /* switch */ 1157190225Srpaulo index++; 1158146768Ssam } 1159146768Ssam 1160190225Srpaulo p->dlt_list[dlt_index++] = DLT_ERF; 1161172677Smlaier 1162190225Srpaulo p->dlt_count = dlt_index; 1163190225Srpaulo 1164190225Srpaulo if(!p->linktype) 1165190225Srpaulo p->linktype = DLT_ERF; 1166190225Srpaulo 1167146768Ssam return p->linktype; 1168127664Sbms} 1169