pcap-dag.c revision 214518
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 51146768Ssam#define ATM_CELL_SIZE 52 52146768Ssam#define ATM_HDR_SIZE 4 53127664Sbms 54172677Smlaier/* 55172677Smlaier * A header containing additional MTP information. 56172677Smlaier */ 57172677Smlaier#define MTP2_SENT_OFFSET 0 /* 1 byte */ 58172677Smlaier#define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */ 59172677Smlaier#define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */ 60172677Smlaier#define MTP2_HDR_LEN 4 /* length of the header */ 61172677Smlaier 62172677Smlaier#define MTP2_ANNEX_A_NOT_USED 0 63172677Smlaier#define MTP2_ANNEX_A_USED 1 64172677Smlaier#define MTP2_ANNEX_A_USED_UNKNOWN 2 65172677Smlaier 66146768Ssam/* SunATM pseudo header */ 67146768Ssamstruct sunatm_hdr { 68146768Ssam unsigned char flags; /* destination and traffic type */ 69146768Ssam unsigned char vpi; /* VPI */ 70146768Ssam unsigned short vci; /* VCI */ 71146768Ssam}; 72146768Ssam 73127664Sbmstypedef struct pcap_dag_node { 74146768Ssam struct pcap_dag_node *next; 75146768Ssam pcap_t *p; 76146768Ssam pid_t pid; 77127664Sbms} pcap_dag_node_t; 78127664Sbms 79127664Sbmsstatic pcap_dag_node_t *pcap_dags = NULL; 80127664Sbmsstatic int atexit_handler_installed = 0; 81127664Sbmsstatic const unsigned short endian_test_word = 0x0100; 82127664Sbms 83127664Sbms#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) 84127664Sbms 85127664Sbms 86127664Sbms#ifdef DAG_ONLY 87127664Sbms/* This code is required when compiling for a DAG device only. */ 88127664Sbms 89127664Sbms/* Replace dag function names with pcap equivalent. */ 90190225Srpaulo#define dag_create pcap_create 91127664Sbms#define dag_platform_finddevs pcap_platform_finddevs 92127664Sbms#endif /* DAG_ONLY */ 93127664Sbms 94172677Smlaier#define MAX_DAG_PACKET 65536 95172677Smlaier 96172677Smlaierstatic unsigned char TempPkt[MAX_DAG_PACKET]; 97172677Smlaier 98127664Sbmsstatic int dag_setfilter(pcap_t *p, struct bpf_program *fp); 99127664Sbmsstatic int dag_stats(pcap_t *p, struct pcap_stat *ps); 100127664Sbmsstatic int dag_set_datalink(pcap_t *p, int dlt); 101127664Sbmsstatic int dag_get_datalink(pcap_t *p); 102127664Sbmsstatic int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf); 103127664Sbms 104146768Ssamstatic void 105146768Ssamdelete_pcap_dag(pcap_t *p) 106146768Ssam{ 107146768Ssam pcap_dag_node_t *curr = NULL, *prev = NULL; 108127664Sbms 109146768Ssam for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { 110146768Ssam /* empty */ 111146768Ssam } 112127664Sbms 113146768Ssam if (curr != NULL && curr->p == p) { 114146768Ssam if (prev != NULL) { 115146768Ssam prev->next = curr->next; 116146768Ssam } else { 117146768Ssam pcap_dags = curr->next; 118146768Ssam } 119146768Ssam } 120127664Sbms} 121127664Sbms 122127664Sbms/* 123127664Sbms * Performs a graceful shutdown of the DAG card, frees dynamic memory held 124127664Sbms * in the pcap_t structure, and closes the file descriptor for the DAG card. 125127664Sbms */ 126127664Sbms 127146768Ssamstatic void 128190225Srpaulodag_platform_cleanup(pcap_t *p) 129146768Ssam{ 130162012Ssam 131162012Ssam if (p != NULL) { 132162012Ssam#ifdef HAVE_DAG_STREAMS_API 133162012Ssam if(dag_stop_stream(p->fd, p->md.dag_stream) < 0) 134162012Ssam fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); 135146768Ssam 136162012Ssam if(dag_detach_stream(p->fd, p->md.dag_stream) < 0) 137162012Ssam fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); 138127664Sbms#else 139146768Ssam if(dag_stop(p->fd) < 0) 140146768Ssam fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 141162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 142190225Srpaulo if(p->fd != -1) { 143190225Srpaulo if(dag_close(p->fd) < 0) 144190225Srpaulo fprintf(stderr,"dag_close: %s\n", strerror(errno)); 145190225Srpaulo p->fd = -1; 146190225Srpaulo } 147190225Srpaulo delete_pcap_dag(p); 148190225Srpaulo pcap_cleanup_live_common(p); 149146768Ssam } 150146768Ssam /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ 151127664Sbms} 152127664Sbms 153146768Ssamstatic void 154146768Ssamatexit_handler(void) 155146768Ssam{ 156146768Ssam while (pcap_dags != NULL) { 157146768Ssam if (pcap_dags->pid == getpid()) { 158190225Srpaulo dag_platform_cleanup(pcap_dags->p); 159146768Ssam } else { 160146768Ssam delete_pcap_dag(pcap_dags->p); 161146768Ssam } 162146768Ssam } 163127664Sbms} 164127664Sbms 165146768Ssamstatic int 166146768Ssamnew_pcap_dag(pcap_t *p) 167146768Ssam{ 168146768Ssam pcap_dag_node_t *node = NULL; 169127664Sbms 170146768Ssam if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { 171146768Ssam return -1; 172146768Ssam } 173127664Sbms 174146768Ssam if (!atexit_handler_installed) { 175146768Ssam atexit(atexit_handler); 176146768Ssam atexit_handler_installed = 1; 177146768Ssam } 178127664Sbms 179146768Ssam node->next = pcap_dags; 180146768Ssam node->p = p; 181146768Ssam node->pid = getpid(); 182127664Sbms 183146768Ssam pcap_dags = node; 184127664Sbms 185146768Ssam return 0; 186127664Sbms} 187127664Sbms 188190225Srpaulostatic unsigned int 189190225Srpaulodag_erf_ext_header_count(uint8_t * erf, size_t len) 190190225Srpaulo{ 191190225Srpaulo uint32_t hdr_num = 0; 192190225Srpaulo uint8_t hdr_type; 193190225Srpaulo 194190225Srpaulo /* basic sanity checks */ 195190225Srpaulo if ( erf == NULL ) 196190225Srpaulo return 0; 197190225Srpaulo if ( len < 16 ) 198190225Srpaulo return 0; 199190225Srpaulo 200190225Srpaulo /* check if we have any extension headers */ 201190225Srpaulo if ( (erf[8] & 0x80) == 0x00 ) 202190225Srpaulo return 0; 203190225Srpaulo 204190225Srpaulo /* loop over the extension headers */ 205190225Srpaulo do { 206190225Srpaulo 207190225Srpaulo /* sanity check we have enough bytes */ 208190225Srpaulo if ( len <= (24 + (hdr_num * 8)) ) 209190225Srpaulo return hdr_num; 210190225Srpaulo 211190225Srpaulo /* get the header type */ 212190225Srpaulo hdr_type = erf[(16 + (hdr_num * 8))]; 213190225Srpaulo hdr_num++; 214190225Srpaulo 215190225Srpaulo } while ( hdr_type & 0x80 ); 216190225Srpaulo 217190225Srpaulo return hdr_num; 218190225Srpaulo} 219190225Srpaulo 220127664Sbms/* 221127664Sbms * Read at most max_packets from the capture stream and call the callback 222127664Sbms * for each of them. Returns the number of packets handled, -1 if an 223127664Sbms * error occured, or -2 if we were told to break out of the loop. 224127664Sbms */ 225146768Ssamstatic int 226146768Ssamdag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 227146768Ssam{ 228127664Sbms unsigned int processed = 0; 229127664Sbms int flags = p->md.dag_offset_flags; 230127664Sbms unsigned int nonblocking = flags & DAGF_NONBLOCK; 231190225Srpaulo unsigned int num_ext_hdr = 0; 232127664Sbms 233162012Ssam /* Get the next bufferful of packets (if necessary). */ 234162012Ssam while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) { 235127664Sbms 236162012Ssam /* 237162012Ssam * Has "pcap_breakloop()" been called? 238162012Ssam */ 239162012Ssam if (p->break_loop) { 240127664Sbms /* 241162012Ssam * Yes - clear the flag that indicates that 242162012Ssam * it has, and return -2 to indicate that 243162012Ssam * we were told to break out of the loop. 244127664Sbms */ 245162012Ssam p->break_loop = 0; 246162012Ssam return -2; 247162012Ssam } 248127664Sbms 249162012Ssam#ifdef HAVE_DAG_STREAMS_API 250162012Ssam /* dag_advance_stream() will block (unless nonblock is called) 251162012Ssam * until 64kB of data has accumulated. 252162012Ssam * If to_ms is set, it will timeout before 64kB has accumulated. 253162012Ssam * We wait for 64kB because processing a few packets at a time 254162012Ssam * can cause problems at high packet rates (>200kpps) due 255162012Ssam * to inefficiencies. 256162012Ssam * This does mean if to_ms is not specified the capture may 'hang' 257162012Ssam * for long periods if the data rate is extremely slow (<64kB/sec) 258162012Ssam * If non-block is specified it will return immediately. The user 259162012Ssam * is then responsible for efficiency. 260162012Ssam */ 261190225Srpaulo if ( NULL == (p->md.dag_mem_top = dag_advance_stream(p->fd, p->md.dag_stream, &(p->md.dag_mem_bottom))) ) { 262190225Srpaulo return -1; 263190225Srpaulo } 264162012Ssam#else 265162012Ssam /* dag_offset does not support timeouts */ 266162012Ssam p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), flags); 267162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 268162012Ssam 269162012Ssam if (nonblocking && (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size)) 270162012Ssam { 271162012Ssam /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ 272162012Ssam return 0; 273127664Sbms } 274162012Ssam 275162012Ssam if(!nonblocking && 276162012Ssam p->md.dag_timeout && 277162012Ssam (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size)) 278162012Ssam { 279162012Ssam /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ 280162012Ssam return 0; 281162012Ssam } 282162012Ssam 283162012Ssam } 284146768Ssam 285162012Ssam /* Process the packets. */ 286162012Ssam while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) { 287190225Srpaulo 288162012Ssam unsigned short packet_len = 0; 289162012Ssam int caplen = 0; 290162012Ssam struct pcap_pkthdr pcap_header; 291190225Srpaulo 292162012Ssam#ifdef HAVE_DAG_STREAMS_API 293162012Ssam dag_record_t *header = (dag_record_t *)(p->md.dag_mem_bottom); 294162012Ssam#else 295162012Ssam dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom); 296162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 297162012Ssam 298190225Srpaulo u_char *dp = ((u_char *)header); /* + dag_record_size; */ 299162012Ssam unsigned short rlen; 300127664Sbms 301162012Ssam /* 302162012Ssam * Has "pcap_breakloop()" been called? 303162012Ssam */ 304162012Ssam if (p->break_loop) { 305127664Sbms /* 306162012Ssam * Yes - clear the flag that indicates that 307162012Ssam * it has, and return -2 to indicate that 308162012Ssam * we were told to break out of the loop. 309127664Sbms */ 310162012Ssam p->break_loop = 0; 311162012Ssam return -2; 312162012Ssam } 313127664Sbms 314162012Ssam rlen = ntohs(header->rlen); 315162012Ssam if (rlen < dag_record_size) 316162012Ssam { 317162012Ssam strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); 318162012Ssam return -1; 319162012Ssam } 320162012Ssam p->md.dag_mem_bottom += rlen; 321162012Ssam 322162012Ssam /* Count lost packets. */ 323190225Srpaulo switch((header->type & 0x7f)) { 324190225Srpaulo /* in these types the color value overwrites the lctr */ 325162012Ssam case TYPE_COLOR_HDLC_POS: 326162012Ssam case TYPE_COLOR_ETH: 327172677Smlaier case TYPE_DSM_COLOR_HDLC_POS: 328172677Smlaier case TYPE_DSM_COLOR_ETH: 329172677Smlaier case TYPE_COLOR_MC_HDLC_POS: 330190225Srpaulo case TYPE_COLOR_HASH_ETH: 331190225Srpaulo case TYPE_COLOR_HASH_POS: 332172677Smlaier break; 333172677Smlaier 334162012Ssam default: 335127664Sbms if (header->lctr) { 336146768Ssam if (p->md.stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { 337127664Sbms p->md.stat.ps_drop = UINT_MAX; 338127664Sbms } else { 339146768Ssam p->md.stat.ps_drop += ntohs(header->lctr); 340127664Sbms } 341127664Sbms } 342162012Ssam } 343190225Srpaulo 344190225Srpaulo if ((header->type & 0x7f) == TYPE_PAD) { 345190225Srpaulo continue; 346190225Srpaulo } 347127664Sbms 348190225Srpaulo num_ext_hdr = dag_erf_ext_header_count(dp, rlen); 349190225Srpaulo 350190225Srpaulo /* ERF encapsulation */ 351190225Srpaulo /* The Extensible Record Format is not dropped for this kind of encapsulation, 352190225Srpaulo * and will be handled as a pseudo header by the decoding application. 353190225Srpaulo * The information carried in the ERF header and in the optional subheader (if present) 354190225Srpaulo * could be merged with the libpcap information, to offer a better decoding. 355190225Srpaulo * The packet length is 356190225Srpaulo * o the length of the packet on the link (header->wlen), 357190225Srpaulo * o plus the length of the ERF header (dag_record_size), as the length of the 358190225Srpaulo * pseudo header will be adjusted during the decoding, 359190225Srpaulo * o plus the length of the optional subheader (if present). 360190225Srpaulo * 361190225Srpaulo * The capture length is header.rlen and the byte stuffing for alignment will be dropped 362190225Srpaulo * if the capture length is greater than the packet length. 363190225Srpaulo */ 364190225Srpaulo if (p->linktype == DLT_ERF) { 365190225Srpaulo packet_len = ntohs(header->wlen) + dag_record_size; 366190225Srpaulo caplen = rlen; 367190225Srpaulo switch ((header->type & 0x7f)) { 368190225Srpaulo case TYPE_MC_AAL5: 369190225Srpaulo case TYPE_MC_ATM: 370190225Srpaulo case TYPE_MC_HDLC: 371214518Srpaulo case TYPE_MC_RAW_CHANNEL: 372214518Srpaulo case TYPE_MC_RAW: 373214518Srpaulo case TYPE_MC_AAL2: 374214518Srpaulo case TYPE_COLOR_MC_HDLC_POS: 375190225Srpaulo packet_len += 4; /* MC header */ 376190225Srpaulo break; 377190225Srpaulo 378190225Srpaulo case TYPE_COLOR_HASH_ETH: 379190225Srpaulo case TYPE_DSM_COLOR_ETH: 380190225Srpaulo case TYPE_COLOR_ETH: 381190225Srpaulo case TYPE_ETH: 382190225Srpaulo packet_len += 2; /* ETH header */ 383190225Srpaulo break; 384190225Srpaulo } /* switch type */ 385190225Srpaulo 386190225Srpaulo /* Include ERF extension headers */ 387190225Srpaulo packet_len += (8 * num_ext_hdr); 388190225Srpaulo 389190225Srpaulo if (caplen > packet_len) { 390190225Srpaulo caplen = packet_len; 391190225Srpaulo } 392190225Srpaulo } else { 393190225Srpaulo /* Other kind of encapsulation according to the header Type */ 394190225Srpaulo 395190225Srpaulo /* Skip over generic ERF header */ 396190225Srpaulo dp += dag_record_size; 397190225Srpaulo /* Skip over extension headers */ 398190225Srpaulo dp += 8 * num_ext_hdr; 399190225Srpaulo 400190225Srpaulo switch((header->type & 0x7f)) { 401190225Srpaulo case TYPE_ATM: 402190225Srpaulo case TYPE_AAL5: 403190225Srpaulo if (header->type == TYPE_AAL5) { 404190225Srpaulo packet_len = ntohs(header->wlen); 405190225Srpaulo caplen = rlen - dag_record_size; 406190225Srpaulo } 407190225Srpaulo case TYPE_MC_ATM: 408190225Srpaulo if (header->type == TYPE_MC_ATM) { 409190225Srpaulo caplen = packet_len = ATM_CELL_SIZE; 410190225Srpaulo dp+=4; 411190225Srpaulo } 412190225Srpaulo case TYPE_MC_AAL5: 413190225Srpaulo if (header->type == TYPE_MC_AAL5) { 414190225Srpaulo packet_len = ntohs(header->wlen); 415190225Srpaulo caplen = rlen - dag_record_size - 4; 416190225Srpaulo dp+=4; 417190225Srpaulo } 418190225Srpaulo if (header->type == TYPE_ATM) { 419190225Srpaulo caplen = packet_len = ATM_CELL_SIZE; 420190225Srpaulo } 421190225Srpaulo if (p->linktype == DLT_SUNATM) { 422190225Srpaulo struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; 423190225Srpaulo unsigned long rawatm; 424190225Srpaulo 425190225Srpaulo rawatm = ntohl(*((unsigned long *)dp)); 426190225Srpaulo sunatm->vci = htons((rawatm >> 4) & 0xffff); 427190225Srpaulo sunatm->vpi = (rawatm >> 20) & 0x00ff; 428190225Srpaulo sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | 429190225Srpaulo ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : 430190225Srpaulo ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : 431190225Srpaulo ((dp[ATM_HDR_SIZE] == 0xaa && 432190225Srpaulo dp[ATM_HDR_SIZE+1] == 0xaa && 433190225Srpaulo dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); 434190225Srpaulo 435190225Srpaulo } else { 436190225Srpaulo packet_len -= ATM_HDR_SIZE; 437190225Srpaulo caplen -= ATM_HDR_SIZE; 438190225Srpaulo dp += ATM_HDR_SIZE; 439190225Srpaulo } 440190225Srpaulo break; 441190225Srpaulo 442190225Srpaulo case TYPE_COLOR_HASH_ETH: 443190225Srpaulo case TYPE_DSM_COLOR_ETH: 444190225Srpaulo case TYPE_COLOR_ETH: 445190225Srpaulo case TYPE_ETH: 446190225Srpaulo packet_len = ntohs(header->wlen); 447190225Srpaulo packet_len -= (p->md.dag_fcs_bits >> 3); 448190225Srpaulo caplen = rlen - dag_record_size - 2; 449190225Srpaulo if (caplen > packet_len) { 450190225Srpaulo caplen = packet_len; 451190225Srpaulo } 452190225Srpaulo dp += 2; 453190225Srpaulo break; 454190225Srpaulo 455190225Srpaulo case TYPE_COLOR_HASH_POS: 456190225Srpaulo case TYPE_DSM_COLOR_HDLC_POS: 457190225Srpaulo case TYPE_COLOR_HDLC_POS: 458190225Srpaulo case TYPE_HDLC_POS: 459190225Srpaulo packet_len = ntohs(header->wlen); 460190225Srpaulo packet_len -= (p->md.dag_fcs_bits >> 3); 461190225Srpaulo caplen = rlen - dag_record_size; 462190225Srpaulo if (caplen > packet_len) { 463190225Srpaulo caplen = packet_len; 464190225Srpaulo } 465190225Srpaulo break; 466190225Srpaulo 467190225Srpaulo case TYPE_COLOR_MC_HDLC_POS: 468190225Srpaulo case TYPE_MC_HDLC: 469190225Srpaulo packet_len = ntohs(header->wlen); 470190225Srpaulo packet_len -= (p->md.dag_fcs_bits >> 3); 471190225Srpaulo caplen = rlen - dag_record_size - 4; 472190225Srpaulo if (caplen > packet_len) { 473190225Srpaulo caplen = packet_len; 474190225Srpaulo } 475190225Srpaulo /* jump the MC_HDLC_HEADER */ 476190225Srpaulo dp += 4; 477190225Srpaulo#ifdef DLT_MTP2_WITH_PHDR 478190225Srpaulo if (p->linktype == DLT_MTP2_WITH_PHDR) { 479190225Srpaulo /* Add the MTP2 Pseudo Header */ 480190225Srpaulo caplen += MTP2_HDR_LEN; 481190225Srpaulo packet_len += MTP2_HDR_LEN; 482190225Srpaulo 483190225Srpaulo TempPkt[MTP2_SENT_OFFSET] = 0; 484190225Srpaulo TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN; 485190225Srpaulo *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01); 486190225Srpaulo *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff); 487190225Srpaulo memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen); 488190225Srpaulo dp = TempPkt; 489190225Srpaulo } 490190225Srpaulo#endif 491190225Srpaulo break; 492190225Srpaulo 493190225Srpaulo case TYPE_IPV4: 494214518Srpaulo case TYPE_IPV6: 495190225Srpaulo packet_len = ntohs(header->wlen); 496190225Srpaulo caplen = rlen - dag_record_size; 497190225Srpaulo if (caplen > packet_len) { 498190225Srpaulo caplen = packet_len; 499190225Srpaulo } 500190225Srpaulo break; 501190225Srpaulo 502214518Srpaulo /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */ 503214518Srpaulo case TYPE_MC_RAW: 504214518Srpaulo case TYPE_MC_RAW_CHANNEL: 505214518Srpaulo case TYPE_IP_COUNTER: 506214518Srpaulo case TYPE_TCP_FLOW_COUNTER: 507214518Srpaulo case TYPE_INFINIBAND: 508214518Srpaulo case TYPE_RAW_LINK: 509214518Srpaulo case TYPE_INFINIBAND_LINK: 510190225Srpaulo default: 511190225Srpaulo /* Unhandled ERF type. 512190225Srpaulo * Ignore rather than generating error 513190225Srpaulo */ 514190225Srpaulo continue; 515190225Srpaulo } /* switch type */ 516190225Srpaulo 517190225Srpaulo /* Skip over extension headers */ 518190225Srpaulo caplen -= (8 * num_ext_hdr); 519190225Srpaulo 520190225Srpaulo } /* ERF encapsulation */ 521190225Srpaulo 522190225Srpaulo if (caplen > p->snapshot) 523190225Srpaulo caplen = p->snapshot; 524190225Srpaulo 525162012Ssam /* Run the packet filter if there is one. */ 526162012Ssam if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { 527190225Srpaulo 528162012Ssam /* convert between timestamp formats */ 529162012Ssam register unsigned long long ts; 530127664Sbms 531162012Ssam if (IS_BIGENDIAN()) { 532172677Smlaier ts = SWAPLL(header->ts); 533162012Ssam } else { 534162012Ssam ts = header->ts; 535162012Ssam } 536127664Sbms 537162012Ssam pcap_header.ts.tv_sec = ts >> 32; 538162012Ssam ts = (ts & 0xffffffffULL) * 1000000; 539162012Ssam ts += 0x80000000; /* rounding */ 540162012Ssam pcap_header.ts.tv_usec = ts >> 32; 541162012Ssam if (pcap_header.ts.tv_usec >= 1000000) { 542162012Ssam pcap_header.ts.tv_usec -= 1000000; 543162012Ssam pcap_header.ts.tv_sec++; 544162012Ssam } 545127664Sbms 546162012Ssam /* Fill in our own header data */ 547162012Ssam pcap_header.caplen = caplen; 548162012Ssam pcap_header.len = packet_len; 549146768Ssam 550162012Ssam /* Count the packet. */ 551162012Ssam p->md.stat.ps_recv++; 552146768Ssam 553162012Ssam /* Call the user supplied callback function */ 554162012Ssam callback(user, &pcap_header, dp); 555146768Ssam 556162012Ssam /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ 557162012Ssam processed++; 558190225Srpaulo if (processed == cnt && cnt > 0) 559162012Ssam { 560162012Ssam /* Reached the user-specified limit. */ 561162012Ssam return cnt; 562127664Sbms } 563127664Sbms } 564162012Ssam } 565127664Sbms 566127664Sbms return processed; 567127664Sbms} 568127664Sbms 569146768Ssamstatic int 570146768Ssamdag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 571146768Ssam{ 572146768Ssam strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", 573146768Ssam PCAP_ERRBUF_SIZE); 574146768Ssam return (-1); 575146768Ssam} 576146768Ssam 577127664Sbms/* 578127664Sbms * Get a handle for a live capture from the given DAG device. Passing a NULL 579127664Sbms * device will result in a failure. The promisc flag is ignored because DAG 580190225Srpaulo * cards are always promiscuous. The to_ms parameter is used in setting the 581190225Srpaulo * API polling parameters. 582127664Sbms * 583172677Smlaier * snaplen is now also ignored, until we get per-stream slen support. Set 584190225Srpaulo * slen with approprite DAG tool BEFORE pcap_activate(). 585172677Smlaier * 586127664Sbms * See also pcap(3). 587127664Sbms */ 588190225Srpaulostatic int dag_activate(pcap_t* handle) 589146768Ssam{ 590190225Srpaulo#if 0 591146768Ssam char conf[30]; /* dag configure string */ 592190225Srpaulo#endif 593146768Ssam char *s; 594146768Ssam int n; 595146768Ssam daginf_t* daginf; 596172677Smlaier char * newDev = NULL; 597190225Srpaulo char * device = handle->opt.source; 598162012Ssam#ifdef HAVE_DAG_STREAMS_API 599162012Ssam uint32_t mindata; 600162012Ssam struct timeval maxwait; 601162012Ssam struct timeval poll; 602162012Ssam#endif 603162012Ssam 604146768Ssam if (device == NULL) { 605190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); 606190225Srpaulo return -1; 607146768Ssam } 608127664Sbms 609146768Ssam /* Initialize some components of the pcap structure. */ 610127664Sbms 611172677Smlaier#ifdef HAVE_DAG_STREAMS_API 612162012Ssam newDev = (char *)malloc(strlen(device) + 16); 613172677Smlaier if (newDev == NULL) { 614190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); 615172677Smlaier goto fail; 616172677Smlaier } 617162012Ssam 618162012Ssam /* Parse input name to get dag device and stream number if provided */ 619162012Ssam if (dag_parse_name(device, newDev, strlen(device) + 16, &handle->md.dag_stream) < 0) { 620190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: %s\n", pcap_strerror(errno)); 621162012Ssam goto fail; 622162012Ssam } 623162012Ssam device = newDev; 624162012Ssam 625162012Ssam if (handle->md.dag_stream%2) { 626190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture\n"); 627162012Ssam goto fail; 628162012Ssam } 629162012Ssam#else 630172677Smlaier if (strncmp(device, "/dev/", 5) != 0) { 631172677Smlaier newDev = (char *)malloc(strlen(device) + 5); 632172677Smlaier if (newDev == NULL) { 633190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); 634172677Smlaier goto fail; 635172677Smlaier } 636172677Smlaier strcpy(newDev, "/dev/"); 637172677Smlaier strcat(newDev, device); 638146768Ssam device = newDev; 639146768Ssam } 640162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 641127664Sbms 642146768Ssam /* setup device parameters */ 643146768Ssam if((handle->fd = dag_open((char *)device)) < 0) { 644190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno)); 645146768Ssam goto fail; 646146768Ssam } 647127664Sbms 648162012Ssam#ifdef HAVE_DAG_STREAMS_API 649162012Ssam /* Open requested stream. Can fail if already locked or on error */ 650162012Ssam if (dag_attach_stream(handle->fd, handle->md.dag_stream, 0, 0) < 0) { 651190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s\n", pcap_strerror(errno)); 652172677Smlaier goto failclose; 653162012Ssam } 654162012Ssam 655162012Ssam /* Set up default poll parameters for stream 656162012Ssam * Can be overridden by pcap_set_nonblock() 657162012Ssam */ 658162012Ssam if (dag_get_stream_poll(handle->fd, handle->md.dag_stream, 659162012Ssam &mindata, &maxwait, &poll) < 0) { 660190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); 661172677Smlaier goto faildetach; 662162012Ssam } 663162012Ssam 664162012Ssam /* Amount of data to collect in Bytes before calling callbacks. 665162012Ssam * Important for efficiency, but can introduce latency 666162012Ssam * at low packet rates if to_ms not set! 667162012Ssam */ 668162012Ssam mindata = 65536; 669162012Ssam 670190225Srpaulo /* Obey md.timeout (was to_ms) if supplied. This is a good idea! 671162012Ssam * Recommend 10-100ms. Calls will time out even if no data arrived. 672162012Ssam */ 673190225Srpaulo maxwait.tv_sec = handle->md.timeout/1000; 674190225Srpaulo maxwait.tv_usec = (handle->md.timeout%1000) * 1000; 675162012Ssam 676162012Ssam if (dag_set_stream_poll(handle->fd, handle->md.dag_stream, 677162012Ssam mindata, &maxwait, &poll) < 0) { 678190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); 679172677Smlaier goto faildetach; 680162012Ssam } 681162012Ssam 682162012Ssam#else 683162012Ssam if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { 684190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno)); 685172677Smlaier goto failclose; 686162012Ssam } 687162012Ssam 688162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 689162012Ssam 690172677Smlaier /* XXX Not calling dag_configure() to set slen; this is unsafe in 691172677Smlaier * multi-stream environments as the gpp config is global. 692172677Smlaier * Once the firmware provides 'per-stream slen' this can be supported 693172677Smlaier * again via the Config API without side-effects */ 694172677Smlaier#if 0 695146768Ssam /* set the card snap length to the specified snaplen parameter */ 696172677Smlaier /* This is a really bad idea, as different cards have different 697172677Smlaier * valid slen ranges. Should fix in Config API. */ 698190225Srpaulo if (handle->snapshot == 0 || handle->snapshot > MAX_DAG_SNAPLEN) { 699190225Srpaulo handle->snapshot = MAX_DAG_SNAPLEN; 700146768Ssam } else if (snaplen < MIN_DAG_SNAPLEN) { 701190225Srpaulo handle->snapshot = MIN_DAG_SNAPLEN; 702146768Ssam } 703146768Ssam /* snap len has to be a multiple of 4 */ 704146768Ssam snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3); 705127664Sbms 706146768Ssam if(dag_configure(handle->fd, conf) < 0) { 707190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno)); 708172677Smlaier goto faildetach; 709146768Ssam } 710172677Smlaier#endif 711172677Smlaier 712162012Ssam#ifdef HAVE_DAG_STREAMS_API 713162012Ssam if(dag_start_stream(handle->fd, handle->md.dag_stream) < 0) { 714190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s\n", device, pcap_strerror(errno)); 715172677Smlaier goto faildetach; 716146768Ssam } 717162012Ssam#else 718146768Ssam if(dag_start(handle->fd) < 0) { 719190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno)); 720172677Smlaier goto failclose; 721146768Ssam } 722162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 723127664Sbms 724146768Ssam /* 725146768Ssam * Important! You have to ensure bottom is properly 726146768Ssam * initialized to zero on startup, it won't give you 727146768Ssam * a compiler warning if you make this mistake! 728146768Ssam */ 729146768Ssam handle->md.dag_mem_bottom = 0; 730146768Ssam handle->md.dag_mem_top = 0; 731127664Sbms 732190225Srpaulo /* 733190225Srpaulo * Find out how many FCS bits we should strip. 734190225Srpaulo * First, query the card to see if it strips the FCS. 735190225Srpaulo */ 736146768Ssam daginf = dag_info(handle->fd); 737190225Srpaulo if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) { 738146768Ssam /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ 739146768Ssam handle->md.dag_fcs_bits = 0; 740127664Sbms 741190225Srpaulo /* Note that no FCS will be supplied. */ 742190225Srpaulo handle->linktype_ext = LT_FCS_DATALINK_EXT(0); 743190225Srpaulo } else { 744190225Srpaulo /* 745190225Srpaulo * Start out assuming it's 32 bits. 746190225Srpaulo */ 747190225Srpaulo handle->md.dag_fcs_bits = 32; 748190225Srpaulo 749190225Srpaulo /* Allow an environment variable to override. */ 750190225Srpaulo if ((s = getenv("ERF_FCS_BITS")) != NULL) { 751190225Srpaulo if ((n = atoi(s)) == 0 || n == 16 || n == 32) { 752190225Srpaulo handle->md.dag_fcs_bits = n; 753190225Srpaulo } else { 754190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 755190225Srpaulo "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n); 756190225Srpaulo goto failstop; 757190225Srpaulo } 758146768Ssam } 759190225Srpaulo 760190225Srpaulo /* 761190225Srpaulo * Did the user request that they not be stripped? 762190225Srpaulo */ 763190225Srpaulo if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) { 764190225Srpaulo /* Yes. Note the number of bytes that will be 765190225Srpaulo supplied. */ 766190225Srpaulo handle->linktype_ext = LT_FCS_DATALINK_EXT(handle->md.dag_fcs_bits/16); 767190225Srpaulo 768190225Srpaulo /* And don't strip them. */ 769190225Srpaulo handle->md.dag_fcs_bits = 0; 770190225Srpaulo } 771146768Ssam } 772127664Sbms 773190225Srpaulo handle->md.dag_timeout = handle->md.timeout; 774127664Sbms 775146768Ssam handle->linktype = -1; 776190225Srpaulo if (dag_get_datalink(handle) < 0) 777172677Smlaier goto failstop; 778146768Ssam 779146768Ssam handle->bufsize = 0; 780127664Sbms 781146768Ssam if (new_pcap_dag(handle) < 0) { 782190225Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno)); 783172677Smlaier goto failstop; 784146768Ssam } 785127664Sbms 786146768Ssam /* 787162012Ssam * "select()" and "poll()" don't work on DAG device descriptors. 788146768Ssam */ 789146768Ssam handle->selectable_fd = -1; 790146768Ssam 791172677Smlaier if (newDev != NULL) { 792172677Smlaier free((char *)newDev); 793172677Smlaier } 794127664Sbms 795146768Ssam handle->read_op = dag_read; 796146768Ssam handle->inject_op = dag_inject; 797146768Ssam handle->setfilter_op = dag_setfilter; 798147894Ssam handle->setdirection_op = NULL; /* Not implemented.*/ 799146768Ssam handle->set_datalink_op = dag_set_datalink; 800146768Ssam handle->getnonblock_op = pcap_getnonblock_fd; 801146768Ssam handle->setnonblock_op = dag_setnonblock; 802146768Ssam handle->stats_op = dag_stats; 803190225Srpaulo handle->cleanup_op = dag_platform_cleanup; 804172677Smlaier handle->md.stat.ps_drop = 0; 805172677Smlaier handle->md.stat.ps_recv = 0; 806214518Srpaulo handle->md.stat.ps_ifdrop = 0; 807190225Srpaulo return 0; 808127664Sbms 809172677Smlaier#ifdef HAVE_DAG_STREAMS_API 810172677Smlaierfailstop: 811190225Srpaulo if (dag_stop_stream(handle->fd, handle->md.dag_stream) < 0) { 812190225Srpaulo fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); 813172677Smlaier } 814172677Smlaier 815172677Smlaierfaildetach: 816190225Srpaulo if (dag_detach_stream(handle->fd, handle->md.dag_stream) < 0) 817190225Srpaulo fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); 818190225Srpaulo#else 819172677Smlaierfailstop: 820190225Srpaulo if (dag_stop(handle->fd) < 0) 821190225Srpaulo fprintf(stderr,"dag_stop: %s\n", strerror(errno)); 822172677Smlaier#endif /* HAVE_DAG_STREAMS_API */ 823172677Smlaier 824172677Smlaierfailclose: 825190225Srpaulo if (dag_close(handle->fd) < 0) 826190225Srpaulo fprintf(stderr,"dag_close: %s\n", strerror(errno)); 827190225Srpaulo delete_pcap_dag(handle); 828190225Srpaulo 829127664Sbmsfail: 830190225Srpaulo pcap_cleanup_live_common(handle); 831162012Ssam if (newDev != NULL) { 832162012Ssam free((char *)newDev); 833146768Ssam } 834127664Sbms 835190225Srpaulo return PCAP_ERROR; 836127664Sbms} 837127664Sbms 838190225Srpaulopcap_t *dag_create(const char *device, char *ebuf) 839190225Srpaulo{ 840190225Srpaulo pcap_t *p; 841190225Srpaulo 842190225Srpaulo p = pcap_create_common(device, ebuf); 843190225Srpaulo if (p == NULL) 844190225Srpaulo return NULL; 845190225Srpaulo 846190225Srpaulo p->activate_op = dag_activate; 847190225Srpaulo return p; 848190225Srpaulo} 849190225Srpaulo 850146768Ssamstatic int 851146768Ssamdag_stats(pcap_t *p, struct pcap_stat *ps) { 852146768Ssam /* This needs to be filled out correctly. Hopefully a dagapi call will 853146768Ssam provide all necessary information. 854146768Ssam */ 855146768Ssam /*p->md.stat.ps_recv = 0;*/ 856146768Ssam /*p->md.stat.ps_drop = 0;*/ 857146768Ssam 858146768Ssam *ps = p->md.stat; 859127664Sbms 860146768Ssam return 0; 861127664Sbms} 862127664Sbms 863127664Sbms/* 864190225Srpaulo * Previously we just generated a list of all possible names and let 865190225Srpaulo * pcap_add_if() attempt to open each one, but with streams this adds up 866190225Srpaulo * to 81 possibilities which is inefficient. 867190225Srpaulo * 868190225Srpaulo * Since we know more about the devices we can prune the tree here. 869190225Srpaulo * pcap_add_if() will still retest each device but the total number of 870190225Srpaulo * open attempts will still be much less than the naive approach. 871127664Sbms */ 872127664Sbmsint 873127664Sbmsdag_platform_finddevs(pcap_if_t **devlistp, char *errbuf) 874127664Sbms{ 875162012Ssam char name[12]; /* XXX - pick a size */ 876146768Ssam int ret = 0; 877162012Ssam int c; 878190225Srpaulo char dagname[DAGNAME_BUFSIZE]; 879190225Srpaulo int dagstream; 880190225Srpaulo int dagfd; 881127664Sbms 882162012Ssam /* Try all the DAGs 0-9 */ 883162012Ssam for (c = 0; c < 9; c++) { 884162012Ssam snprintf(name, 12, "dag%d", c); 885190225Srpaulo if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream)) 886190225Srpaulo { 887190225Srpaulo return -1; 888146768Ssam } 889190225Srpaulo if ( (dagfd = dag_open(dagname)) >= 0 ) { 890190225Srpaulo if (pcap_add_if(devlistp, name, 0, NULL, errbuf) == -1) { 891190225Srpaulo /* 892190225Srpaulo * Failure. 893190225Srpaulo */ 894190225Srpaulo ret = -1; 895190225Srpaulo } 896162012Ssam#ifdef HAVE_DAG_STREAMS_API 897190225Srpaulo { 898190225Srpaulo int stream, rxstreams; 899190225Srpaulo rxstreams = dag_rx_get_stream_count(dagfd); 900190225Srpaulo for(stream=0;stream<16;stream+=2) { 901190225Srpaulo if (0 == dag_attach_stream(dagfd, stream, 0, 0)) { 902190225Srpaulo dag_detach_stream(dagfd, stream); 903190225Srpaulo 904190225Srpaulo snprintf(name, 10, "dag%d:%d", c, stream); 905190225Srpaulo if (pcap_add_if(devlistp, name, 0, NULL, errbuf) == -1) { 906190225Srpaulo /* 907190225Srpaulo * Failure. 908190225Srpaulo */ 909190225Srpaulo ret = -1; 910190225Srpaulo } 911190225Srpaulo } 912190225Srpaulo } 913190225Srpaulo } 914190225Srpaulo#endif /* HAVE_DAG_STREAMS_API */ 915190225Srpaulo dag_close(dagfd); 916146768Ssam } 917190225Srpaulo 918146768Ssam } 919146768Ssam return (ret); 920127664Sbms} 921127664Sbms 922127664Sbms/* 923127664Sbms * Installs the given bpf filter program in the given pcap structure. There is 924127664Sbms * no attempt to store the filter in kernel memory as that is not supported 925127664Sbms * with DAG cards. 926127664Sbms */ 927146768Ssamstatic int 928146768Ssamdag_setfilter(pcap_t *p, struct bpf_program *fp) 929146768Ssam{ 930146768Ssam if (!p) 931146768Ssam return -1; 932146768Ssam if (!fp) { 933146768Ssam strncpy(p->errbuf, "setfilter: No filter specified", 934146768Ssam sizeof(p->errbuf)); 935146768Ssam return -1; 936146768Ssam } 937127664Sbms 938146768Ssam /* Make our private copy of the filter */ 939127664Sbms 940146768Ssam if (install_bpf_program(p, fp) < 0) 941146768Ssam return -1; 942127664Sbms 943146768Ssam p->md.use_bpf = 0; 944127664Sbms 945146768Ssam return (0); 946127664Sbms} 947127664Sbms 948127664Sbmsstatic int 949127664Sbmsdag_set_datalink(pcap_t *p, int dlt) 950127664Sbms{ 951146768Ssam p->linktype = dlt; 952146768Ssam 953127664Sbms return (0); 954127664Sbms} 955127664Sbms 956127664Sbmsstatic int 957127664Sbmsdag_setnonblock(pcap_t *p, int nonblock, char *errbuf) 958127664Sbms{ 959127664Sbms /* 960127664Sbms * Set non-blocking mode on the FD. 961127664Sbms * XXX - is that necessary? If not, don't bother calling it, 962127664Sbms * and have a "dag_getnonblock()" function that looks at 963127664Sbms * "p->md.dag_offset_flags". 964127664Sbms */ 965127664Sbms if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0) 966127664Sbms return (-1); 967162012Ssam#ifdef HAVE_DAG_STREAMS_API 968162012Ssam { 969162012Ssam uint32_t mindata; 970162012Ssam struct timeval maxwait; 971162012Ssam struct timeval poll; 972162012Ssam 973162012Ssam if (dag_get_stream_poll(p->fd, p->md.dag_stream, 974162012Ssam &mindata, &maxwait, &poll) < 0) { 975162012Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); 976162012Ssam return -1; 977162012Ssam } 978162012Ssam 979162012Ssam /* Amount of data to collect in Bytes before calling callbacks. 980162012Ssam * Important for efficiency, but can introduce latency 981162012Ssam * at low packet rates if to_ms not set! 982162012Ssam */ 983162012Ssam if(nonblock) 984162012Ssam mindata = 0; 985162012Ssam else 986162012Ssam mindata = 65536; 987162012Ssam 988162012Ssam if (dag_set_stream_poll(p->fd, p->md.dag_stream, 989162012Ssam mindata, &maxwait, &poll) < 0) { 990162012Ssam snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); 991162012Ssam return -1; 992162012Ssam } 993162012Ssam } 994162012Ssam#endif /* HAVE_DAG_STREAMS_API */ 995127664Sbms if (nonblock) { 996127664Sbms p->md.dag_offset_flags |= DAGF_NONBLOCK; 997127664Sbms } else { 998127664Sbms p->md.dag_offset_flags &= ~DAGF_NONBLOCK; 999127664Sbms } 1000127664Sbms return (0); 1001127664Sbms} 1002127664Sbms 1003127664Sbmsstatic int 1004127664Sbmsdag_get_datalink(pcap_t *p) 1005127664Sbms{ 1006190225Srpaulo int index=0, dlt_index=0; 1007172677Smlaier uint8_t types[255]; 1008127664Sbms 1009172677Smlaier memset(types, 0, 255); 1010172677Smlaier 1011172677Smlaier if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) { 1012146768Ssam (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); 1013146768Ssam return (-1); 1014146768Ssam } 1015127664Sbms 1016172677Smlaier p->linktype = 0; 1017172677Smlaier 1018190225Srpaulo#ifdef HAVE_DAG_GET_STREAM_ERF_TYPES 1019172677Smlaier /* Get list of possible ERF types for this card */ 1020190225Srpaulo if (dag_get_stream_erf_types(p->fd, p->md.dag_stream, types, 255) < 0) { 1021190225Srpaulo snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_stream_erf_types: %s", pcap_strerror(errno)); 1022190225Srpaulo return (-1); 1023190225Srpaulo } 1024190225Srpaulo 1025190225Srpaulo while (types[index]) { 1026190225Srpaulo 1027190225Srpaulo#elif defined HAVE_DAG_GET_ERF_TYPES 1028190225Srpaulo /* Get list of possible ERF types for this card */ 1029172677Smlaier if (dag_get_erf_types(p->fd, types, 255) < 0) { 1030172677Smlaier snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_erf_types: %s", pcap_strerror(errno)); 1031172677Smlaier return (-1); 1032172677Smlaier } 1033172677Smlaier 1034172677Smlaier while (types[index]) { 1035172677Smlaier#else 1036146768Ssam /* Check the type through a dagapi call. */ 1037172677Smlaier types[index] = dag_linktype(p->fd); 1038127664Sbms 1039172677Smlaier { 1040172677Smlaier#endif 1041190225Srpaulo switch((types[index] & 0x7f)) { 1042127664Sbms 1043172677Smlaier case TYPE_HDLC_POS: 1044172677Smlaier case TYPE_COLOR_HDLC_POS: 1045172677Smlaier case TYPE_DSM_COLOR_HDLC_POS: 1046190225Srpaulo case TYPE_COLOR_HASH_POS: 1047190225Srpaulo 1048172677Smlaier if (p->dlt_list != NULL) { 1049190225Srpaulo p->dlt_list[dlt_index++] = DLT_CHDLC; 1050190225Srpaulo p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; 1051190225Srpaulo p->dlt_list[dlt_index++] = DLT_FRELAY; 1052172677Smlaier } 1053172677Smlaier if(!p->linktype) 1054172677Smlaier p->linktype = DLT_CHDLC; 1055172677Smlaier break; 1056146768Ssam 1057172677Smlaier case TYPE_ETH: 1058172677Smlaier case TYPE_COLOR_ETH: 1059172677Smlaier case TYPE_DSM_COLOR_ETH: 1060190225Srpaulo case TYPE_COLOR_HASH_ETH: 1061172677Smlaier /* 1062172677Smlaier * This is (presumably) a real Ethernet capture; give it a 1063172677Smlaier * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 1064172677Smlaier * that an application can let you choose it, in case you're 1065172677Smlaier * capturing DOCSIS traffic that a Cisco Cable Modem 1066172677Smlaier * Termination System is putting out onto an Ethernet (it 1067172677Smlaier * doesn't put an Ethernet header onto the wire, it puts raw 1068172677Smlaier * DOCSIS frames out on the wire inside the low-level 1069172677Smlaier * Ethernet framing). 1070172677Smlaier */ 1071172677Smlaier if (p->dlt_list != NULL) { 1072190225Srpaulo p->dlt_list[dlt_index++] = DLT_EN10MB; 1073190225Srpaulo p->dlt_list[dlt_index++] = DLT_DOCSIS; 1074172677Smlaier } 1075172677Smlaier if(!p->linktype) 1076172677Smlaier p->linktype = DLT_EN10MB; 1077172677Smlaier break; 1078146768Ssam 1079172677Smlaier case TYPE_ATM: 1080172677Smlaier case TYPE_AAL5: 1081172677Smlaier case TYPE_MC_ATM: 1082172677Smlaier case TYPE_MC_AAL5: 1083172677Smlaier if (p->dlt_list != NULL) { 1084190225Srpaulo p->dlt_list[dlt_index++] = DLT_ATM_RFC1483; 1085190225Srpaulo p->dlt_list[dlt_index++] = DLT_SUNATM; 1086172677Smlaier } 1087172677Smlaier if(!p->linktype) 1088172677Smlaier p->linktype = DLT_ATM_RFC1483; 1089172677Smlaier break; 1090146768Ssam 1091172677Smlaier case TYPE_COLOR_MC_HDLC_POS: 1092172677Smlaier case TYPE_MC_HDLC: 1093172677Smlaier if (p->dlt_list != NULL) { 1094190225Srpaulo p->dlt_list[dlt_index++] = DLT_CHDLC; 1095190225Srpaulo p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; 1096190225Srpaulo p->dlt_list[dlt_index++] = DLT_FRELAY; 1097190225Srpaulo p->dlt_list[dlt_index++] = DLT_MTP2; 1098190225Srpaulo p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR; 1099190225Srpaulo p->dlt_list[dlt_index++] = DLT_LAPD; 1100172677Smlaier } 1101172677Smlaier if(!p->linktype) 1102172677Smlaier p->linktype = DLT_CHDLC; 1103172677Smlaier break; 1104146768Ssam 1105190225Srpaulo case TYPE_IPV4: 1106214518Srpaulo case TYPE_IPV6: 1107172677Smlaier if(!p->linktype) 1108190225Srpaulo p->linktype = DLT_RAW; 1109172677Smlaier break; 1110146768Ssam 1111190225Srpaulo case TYPE_LEGACY: 1112190225Srpaulo case TYPE_MC_RAW: 1113190225Srpaulo case TYPE_MC_RAW_CHANNEL: 1114190225Srpaulo case TYPE_IP_COUNTER: 1115190225Srpaulo case TYPE_TCP_FLOW_COUNTER: 1116190225Srpaulo case TYPE_INFINIBAND: 1117214518Srpaulo case TYPE_RAW_LINK: 1118214518Srpaulo case TYPE_INFINIBAND_LINK: 1119172677Smlaier default: 1120190225Srpaulo /* Libpcap cannot deal with these types yet */ 1121214518Srpaulo /* Add no 'native' DLTs, but still covered by DLT_ERF */ 1122190225Srpaulo break; 1123146768Ssam 1124172677Smlaier } /* switch */ 1125190225Srpaulo index++; 1126146768Ssam } 1127146768Ssam 1128190225Srpaulo p->dlt_list[dlt_index++] = DLT_ERF; 1129172677Smlaier 1130190225Srpaulo p->dlt_count = dlt_index; 1131190225Srpaulo 1132190225Srpaulo if(!p->linktype) 1133190225Srpaulo p->linktype = DLT_ERF; 1134190225Srpaulo 1135146768Ssam return p->linktype; 1136127664Sbms} 1137