1335640Shselasky/* 2356341Scy * pcap-dag.c: Packet capture interface for Endace DAG cards. 3335640Shselasky * 4335640Shselasky * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com) 5335640Shselasky * Modifications: Jesper Peterson 6335640Shselasky * Koryn Grant 7356341Scy * Stephen Donnelly <stephen.donnelly@endace.com> 8335640Shselasky */ 9335640Shselasky 10335640Shselasky#ifdef HAVE_CONFIG_H 11335640Shselasky#include <config.h> 12335640Shselasky#endif 13335640Shselasky 14335640Shselasky#include <sys/param.h> /* optionally get BSD define */ 15335640Shselasky 16335640Shselasky#include <stdlib.h> 17335640Shselasky#include <string.h> 18335640Shselasky#include <errno.h> 19335640Shselasky 20335640Shselasky#include "pcap-int.h" 21335640Shselasky 22335640Shselasky#include <ctype.h> 23335640Shselasky#include <netinet/in.h> 24335640Shselasky#include <sys/mman.h> 25335640Shselasky#include <sys/socket.h> 26335640Shselasky#include <sys/types.h> 27335640Shselasky#include <unistd.h> 28335640Shselasky 29335640Shselaskystruct mbuf; /* Squelch compiler warnings on some platforms for */ 30335640Shselaskystruct rtentry; /* declarations in <net/if.h> */ 31335640Shselasky#include <net/if.h> 32335640Shselasky 33335640Shselasky#include "dagnew.h" 34335640Shselasky#include "dagapi.h" 35335640Shselasky#include "dagpci.h" 36335640Shselasky#include "dag_config_api.h" 37335640Shselasky 38335640Shselasky#include "pcap-dag.h" 39335640Shselasky 40335640Shselasky/* 41335640Shselasky * DAG devices have names beginning with "dag", followed by a number 42335640Shselasky * from 0 to DAG_MAX_BOARDS, then optionally a colon and a stream number 43335640Shselasky * from 0 to DAG_STREAM_MAX. 44335640Shselasky */ 45335640Shselasky#ifndef DAG_MAX_BOARDS 46335640Shselasky#define DAG_MAX_BOARDS 32 47335640Shselasky#endif 48335640Shselasky 49335640Shselasky 50335640Shselasky#ifndef ERF_TYPE_AAL5 51335640Shselasky#define ERF_TYPE_AAL5 4 52335640Shselasky#endif 53335640Shselasky 54335640Shselasky#ifndef ERF_TYPE_MC_HDLC 55335640Shselasky#define ERF_TYPE_MC_HDLC 5 56335640Shselasky#endif 57335640Shselasky 58335640Shselasky#ifndef ERF_TYPE_MC_RAW 59335640Shselasky#define ERF_TYPE_MC_RAW 6 60335640Shselasky#endif 61335640Shselasky 62335640Shselasky#ifndef ERF_TYPE_MC_ATM 63335640Shselasky#define ERF_TYPE_MC_ATM 7 64335640Shselasky#endif 65335640Shselasky 66335640Shselasky#ifndef ERF_TYPE_MC_RAW_CHANNEL 67335640Shselasky#define ERF_TYPE_MC_RAW_CHANNEL 8 68335640Shselasky#endif 69335640Shselasky 70335640Shselasky#ifndef ERF_TYPE_MC_AAL5 71335640Shselasky#define ERF_TYPE_MC_AAL5 9 72335640Shselasky#endif 73335640Shselasky 74335640Shselasky#ifndef ERF_TYPE_COLOR_HDLC_POS 75335640Shselasky#define ERF_TYPE_COLOR_HDLC_POS 10 76335640Shselasky#endif 77335640Shselasky 78335640Shselasky#ifndef ERF_TYPE_COLOR_ETH 79335640Shselasky#define ERF_TYPE_COLOR_ETH 11 80335640Shselasky#endif 81335640Shselasky 82335640Shselasky#ifndef ERF_TYPE_MC_AAL2 83335640Shselasky#define ERF_TYPE_MC_AAL2 12 84335640Shselasky#endif 85335640Shselasky 86335640Shselasky#ifndef ERF_TYPE_IP_COUNTER 87335640Shselasky#define ERF_TYPE_IP_COUNTER 13 88335640Shselasky#endif 89335640Shselasky 90335640Shselasky#ifndef ERF_TYPE_TCP_FLOW_COUNTER 91335640Shselasky#define ERF_TYPE_TCP_FLOW_COUNTER 14 92335640Shselasky#endif 93335640Shselasky 94335640Shselasky#ifndef ERF_TYPE_DSM_COLOR_HDLC_POS 95335640Shselasky#define ERF_TYPE_DSM_COLOR_HDLC_POS 15 96335640Shselasky#endif 97335640Shselasky 98335640Shselasky#ifndef ERF_TYPE_DSM_COLOR_ETH 99335640Shselasky#define ERF_TYPE_DSM_COLOR_ETH 16 100335640Shselasky#endif 101335640Shselasky 102335640Shselasky#ifndef ERF_TYPE_COLOR_MC_HDLC_POS 103335640Shselasky#define ERF_TYPE_COLOR_MC_HDLC_POS 17 104335640Shselasky#endif 105335640Shselasky 106335640Shselasky#ifndef ERF_TYPE_AAL2 107335640Shselasky#define ERF_TYPE_AAL2 18 108335640Shselasky#endif 109335640Shselasky 110335640Shselasky#ifndef ERF_TYPE_COLOR_HASH_POS 111335640Shselasky#define ERF_TYPE_COLOR_HASH_POS 19 112335640Shselasky#endif 113335640Shselasky 114335640Shselasky#ifndef ERF_TYPE_COLOR_HASH_ETH 115335640Shselasky#define ERF_TYPE_COLOR_HASH_ETH 20 116335640Shselasky#endif 117335640Shselasky 118335640Shselasky#ifndef ERF_TYPE_INFINIBAND 119335640Shselasky#define ERF_TYPE_INFINIBAND 21 120335640Shselasky#endif 121335640Shselasky 122335640Shselasky#ifndef ERF_TYPE_IPV4 123335640Shselasky#define ERF_TYPE_IPV4 22 124335640Shselasky#endif 125335640Shselasky 126335640Shselasky#ifndef ERF_TYPE_IPV6 127335640Shselasky#define ERF_TYPE_IPV6 23 128335640Shselasky#endif 129335640Shselasky 130335640Shselasky#ifndef ERF_TYPE_RAW_LINK 131335640Shselasky#define ERF_TYPE_RAW_LINK 24 132335640Shselasky#endif 133335640Shselasky 134335640Shselasky#ifndef ERF_TYPE_INFINIBAND_LINK 135335640Shselasky#define ERF_TYPE_INFINIBAND_LINK 25 136335640Shselasky#endif 137335640Shselasky 138335640Shselasky#ifndef ERF_TYPE_META 139335640Shselasky#define ERF_TYPE_META 27 140335640Shselasky#endif 141335640Shselasky 142335640Shselasky#ifndef ERF_TYPE_PAD 143335640Shselasky#define ERF_TYPE_PAD 48 144335640Shselasky#endif 145335640Shselasky 146335640Shselasky#define ATM_CELL_SIZE 52 147335640Shselasky#define ATM_HDR_SIZE 4 148335640Shselasky 149335640Shselasky/* 150335640Shselasky * A header containing additional MTP information. 151335640Shselasky */ 152335640Shselasky#define MTP2_SENT_OFFSET 0 /* 1 byte */ 153335640Shselasky#define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */ 154335640Shselasky#define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */ 155335640Shselasky#define MTP2_HDR_LEN 4 /* length of the header */ 156335640Shselasky 157335640Shselasky#define MTP2_ANNEX_A_NOT_USED 0 158335640Shselasky#define MTP2_ANNEX_A_USED 1 159335640Shselasky#define MTP2_ANNEX_A_USED_UNKNOWN 2 160335640Shselasky 161335640Shselasky/* SunATM pseudo header */ 162335640Shselaskystruct sunatm_hdr { 163335640Shselasky unsigned char flags; /* destination and traffic type */ 164335640Shselasky unsigned char vpi; /* VPI */ 165335640Shselasky unsigned short vci; /* VCI */ 166335640Shselasky}; 167335640Shselasky 168335640Shselasky/* 169335640Shselasky * Private data for capturing on DAG devices. 170335640Shselasky */ 171335640Shselaskystruct pcap_dag { 172335640Shselasky struct pcap_stat stat; 173335640Shselasky u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */ 174335640Shselasky u_char *dag_mem_top; /* DAG card current memory top pointer */ 175335640Shselasky int dag_fcs_bits; /* Number of checksum bits from link layer */ 176335640Shselasky int dag_flags; /* Flags */ 177335640Shselasky int dag_stream; /* DAG stream number */ 178335640Shselasky int dag_timeout; /* timeout specified to pcap_open_live. 179335640Shselasky * Same as in linux above, introduce 180335640Shselasky * generally? */ 181335640Shselasky dag_card_ref_t dag_ref; /* DAG Configuration/Status API card reference */ 182335640Shselasky dag_component_t dag_root; /* DAG CSAPI Root component */ 183335640Shselasky attr_uuid_t drop_attr; /* DAG Stream Drop Attribute handle, if available */ 184335640Shselasky struct timeval required_select_timeout; 185335640Shselasky /* Timeout caller must use in event loops */ 186335640Shselasky}; 187335640Shselasky 188335640Shselaskytypedef struct pcap_dag_node { 189335640Shselasky struct pcap_dag_node *next; 190335640Shselasky pcap_t *p; 191335640Shselasky pid_t pid; 192335640Shselasky} pcap_dag_node_t; 193335640Shselasky 194335640Shselaskystatic pcap_dag_node_t *pcap_dags = NULL; 195335640Shselaskystatic int atexit_handler_installed = 0; 196335640Shselaskystatic const unsigned short endian_test_word = 0x0100; 197335640Shselasky 198335640Shselasky#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) 199335640Shselasky 200335640Shselasky#define MAX_DAG_PACKET 65536 201335640Shselasky 202335640Shselaskystatic unsigned char TempPkt[MAX_DAG_PACKET]; 203335640Shselasky 204335640Shselasky#ifndef HAVE_DAG_LARGE_STREAMS_API 205335640Shselasky#define dag_attach_stream64(a, b, c, d) dag_attach_stream(a, b, c, d) 206335640Shselasky#define dag_get_stream_poll64(a, b, c, d, e) dag_get_stream_poll(a, b, c, d, e) 207335640Shselasky#define dag_set_stream_poll64(a, b, c, d, e) dag_set_stream_poll(a, b, c, d, e) 208335640Shselasky#define dag_size_t uint32_t 209335640Shselasky#endif 210335640Shselasky 211335640Shselaskystatic int dag_setfilter(pcap_t *p, struct bpf_program *fp); 212335640Shselaskystatic int dag_stats(pcap_t *p, struct pcap_stat *ps); 213335640Shselaskystatic int dag_set_datalink(pcap_t *p, int dlt); 214335640Shselaskystatic int dag_get_datalink(pcap_t *p); 215335640Shselaskystatic int dag_setnonblock(pcap_t *p, int nonblock); 216335640Shselasky 217335640Shselaskystatic void 218335640Shselaskydelete_pcap_dag(pcap_t *p) 219335640Shselasky{ 220335640Shselasky pcap_dag_node_t *curr = NULL, *prev = NULL; 221335640Shselasky 222335640Shselasky for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) { 223335640Shselasky /* empty */ 224335640Shselasky } 225335640Shselasky 226335640Shselasky if (curr != NULL && curr->p == p) { 227335640Shselasky if (prev != NULL) { 228335640Shselasky prev->next = curr->next; 229335640Shselasky } else { 230335640Shselasky pcap_dags = curr->next; 231335640Shselasky } 232335640Shselasky } 233335640Shselasky} 234335640Shselasky 235335640Shselasky/* 236335640Shselasky * Performs a graceful shutdown of the DAG card, frees dynamic memory held 237335640Shselasky * in the pcap_t structure, and closes the file descriptor for the DAG card. 238335640Shselasky */ 239335640Shselasky 240335640Shselaskystatic void 241335640Shselaskydag_platform_cleanup(pcap_t *p) 242335640Shselasky{ 243335640Shselasky struct pcap_dag *pd = p->priv; 244335640Shselasky 245335640Shselasky if(dag_stop_stream(p->fd, pd->dag_stream) < 0) 246335640Shselasky fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); 247335640Shselasky 248335640Shselasky if(dag_detach_stream(p->fd, pd->dag_stream) < 0) 249335640Shselasky fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); 250335640Shselasky 251335640Shselasky if(pd->dag_ref != NULL) { 252335640Shselasky dag_config_dispose(pd->dag_ref); 253356341Scy /* 254356341Scy * Note: we don't need to call close(p->fd) or 255356341Scy * dag_close(p->fd), as dag_config_dispose(pd->dag_ref) 256356341Scy * does this. 257356341Scy * 258356341Scy * Set p->fd to -1 to make sure that's not done. 259356341Scy */ 260335640Shselasky p->fd = -1; 261335640Shselasky pd->dag_ref = NULL; 262335640Shselasky } 263335640Shselasky delete_pcap_dag(p); 264335640Shselasky pcap_cleanup_live_common(p); 265335640Shselasky} 266335640Shselasky 267335640Shselaskystatic void 268335640Shselaskyatexit_handler(void) 269335640Shselasky{ 270335640Shselasky while (pcap_dags != NULL) { 271335640Shselasky if (pcap_dags->pid == getpid()) { 272335640Shselasky if (pcap_dags->p != NULL) 273335640Shselasky dag_platform_cleanup(pcap_dags->p); 274335640Shselasky } else { 275335640Shselasky delete_pcap_dag(pcap_dags->p); 276335640Shselasky } 277335640Shselasky } 278335640Shselasky} 279335640Shselasky 280335640Shselaskystatic int 281335640Shselaskynew_pcap_dag(pcap_t *p) 282335640Shselasky{ 283335640Shselasky pcap_dag_node_t *node = NULL; 284335640Shselasky 285335640Shselasky if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) { 286335640Shselasky return -1; 287335640Shselasky } 288335640Shselasky 289335640Shselasky if (!atexit_handler_installed) { 290335640Shselasky atexit(atexit_handler); 291335640Shselasky atexit_handler_installed = 1; 292335640Shselasky } 293335640Shselasky 294335640Shselasky node->next = pcap_dags; 295335640Shselasky node->p = p; 296335640Shselasky node->pid = getpid(); 297335640Shselasky 298335640Shselasky pcap_dags = node; 299335640Shselasky 300335640Shselasky return 0; 301335640Shselasky} 302335640Shselasky 303335640Shselaskystatic unsigned int 304335640Shselaskydag_erf_ext_header_count(uint8_t * erf, size_t len) 305335640Shselasky{ 306335640Shselasky uint32_t hdr_num = 0; 307335640Shselasky uint8_t hdr_type; 308335640Shselasky 309335640Shselasky /* basic sanity checks */ 310335640Shselasky if ( erf == NULL ) 311335640Shselasky return 0; 312335640Shselasky if ( len < 16 ) 313335640Shselasky return 0; 314335640Shselasky 315335640Shselasky /* check if we have any extension headers */ 316335640Shselasky if ( (erf[8] & 0x80) == 0x00 ) 317335640Shselasky return 0; 318335640Shselasky 319335640Shselasky /* loop over the extension headers */ 320335640Shselasky do { 321335640Shselasky 322335640Shselasky /* sanity check we have enough bytes */ 323335640Shselasky if ( len < (24 + (hdr_num * 8)) ) 324335640Shselasky return hdr_num; 325335640Shselasky 326335640Shselasky /* get the header type */ 327335640Shselasky hdr_type = erf[(16 + (hdr_num * 8))]; 328335640Shselasky hdr_num++; 329335640Shselasky 330335640Shselasky } while ( hdr_type & 0x80 ); 331335640Shselasky 332335640Shselasky return hdr_num; 333335640Shselasky} 334335640Shselasky 335335640Shselasky/* 336335640Shselasky * Read at most max_packets from the capture stream and call the callback 337335640Shselasky * for each of them. Returns the number of packets handled, -1 if an 338335640Shselasky * error occured, or -2 if we were told to break out of the loop. 339335640Shselasky */ 340335640Shselaskystatic int 341335640Shselaskydag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 342335640Shselasky{ 343335640Shselasky struct pcap_dag *pd = p->priv; 344335640Shselasky unsigned int processed = 0; 345335640Shselasky unsigned int nonblocking = pd->dag_flags & DAGF_NONBLOCK; 346335640Shselasky unsigned int num_ext_hdr = 0; 347335640Shselasky unsigned int ticks_per_second; 348335640Shselasky 349335640Shselasky /* Get the next bufferful of packets (if necessary). */ 350335640Shselasky while (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size) { 351335640Shselasky 352335640Shselasky /* 353335640Shselasky * Has "pcap_breakloop()" been called? 354335640Shselasky */ 355335640Shselasky if (p->break_loop) { 356335640Shselasky /* 357335640Shselasky * Yes - clear the flag that indicates that 358335640Shselasky * it has, and return -2 to indicate that 359335640Shselasky * we were told to break out of the loop. 360335640Shselasky */ 361335640Shselasky p->break_loop = 0; 362335640Shselasky return -2; 363335640Shselasky } 364335640Shselasky 365335640Shselasky /* dag_advance_stream() will block (unless nonblock is called) 366335640Shselasky * until 64kB of data has accumulated. 367335640Shselasky * If to_ms is set, it will timeout before 64kB has accumulated. 368335640Shselasky * We wait for 64kB because processing a few packets at a time 369335640Shselasky * can cause problems at high packet rates (>200kpps) due 370335640Shselasky * to inefficiencies. 371335640Shselasky * This does mean if to_ms is not specified the capture may 'hang' 372335640Shselasky * for long periods if the data rate is extremely slow (<64kB/sec) 373335640Shselasky * If non-block is specified it will return immediately. The user 374335640Shselasky * is then responsible for efficiency. 375335640Shselasky */ 376335640Shselasky if ( NULL == (pd->dag_mem_top = dag_advance_stream(p->fd, pd->dag_stream, &(pd->dag_mem_bottom))) ) { 377335640Shselasky return -1; 378335640Shselasky } 379335640Shselasky 380335640Shselasky if (nonblocking && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) 381335640Shselasky { 382335640Shselasky /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ 383335640Shselasky return 0; 384335640Shselasky } 385335640Shselasky 386335640Shselasky if(!nonblocking && 387335640Shselasky pd->dag_timeout && 388335640Shselasky (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) 389335640Shselasky { 390335640Shselasky /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ 391335640Shselasky return 0; 392335640Shselasky } 393335640Shselasky 394335640Shselasky } 395335640Shselasky 396335640Shselasky /* Process the packets. */ 397335640Shselasky while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) { 398335640Shselasky 399335640Shselasky unsigned short packet_len = 0; 400335640Shselasky int caplen = 0; 401335640Shselasky struct pcap_pkthdr pcap_header; 402335640Shselasky 403335640Shselasky dag_record_t *header = (dag_record_t *)(pd->dag_mem_bottom); 404335640Shselasky 405335640Shselasky u_char *dp = ((u_char *)header); /* + dag_record_size; */ 406335640Shselasky unsigned short rlen; 407335640Shselasky 408335640Shselasky /* 409335640Shselasky * Has "pcap_breakloop()" been called? 410335640Shselasky */ 411335640Shselasky if (p->break_loop) { 412335640Shselasky /* 413335640Shselasky * Yes - clear the flag that indicates that 414335640Shselasky * it has, and return -2 to indicate that 415335640Shselasky * we were told to break out of the loop. 416335640Shselasky */ 417335640Shselasky p->break_loop = 0; 418335640Shselasky return -2; 419335640Shselasky } 420335640Shselasky 421335640Shselasky rlen = ntohs(header->rlen); 422335640Shselasky if (rlen < dag_record_size) 423335640Shselasky { 424335640Shselasky strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); 425335640Shselasky return -1; 426335640Shselasky } 427335640Shselasky pd->dag_mem_bottom += rlen; 428335640Shselasky 429335640Shselasky /* Count lost packets. */ 430335640Shselasky switch((header->type & 0x7f)) { 431335640Shselasky /* in these types the color value overwrites the lctr */ 432335640Shselasky case ERF_TYPE_COLOR_HDLC_POS: 433335640Shselasky case ERF_TYPE_COLOR_ETH: 434335640Shselasky case ERF_TYPE_DSM_COLOR_HDLC_POS: 435335640Shselasky case ERF_TYPE_DSM_COLOR_ETH: 436335640Shselasky case ERF_TYPE_COLOR_MC_HDLC_POS: 437335640Shselasky case ERF_TYPE_COLOR_HASH_ETH: 438335640Shselasky case ERF_TYPE_COLOR_HASH_POS: 439335640Shselasky break; 440335640Shselasky 441335640Shselasky default: 442335640Shselasky if ( (pd->drop_attr == kNullAttributeUuid) && (header->lctr) ) { 443335640Shselasky pd->stat.ps_drop += ntohs(header->lctr); 444335640Shselasky } 445335640Shselasky } 446335640Shselasky 447335640Shselasky if ((header->type & 0x7f) == ERF_TYPE_PAD) { 448335640Shselasky continue; 449335640Shselasky } 450335640Shselasky 451335640Shselasky num_ext_hdr = dag_erf_ext_header_count(dp, rlen); 452335640Shselasky 453335640Shselasky /* ERF encapsulation */ 454335640Shselasky /* The Extensible Record Format is not dropped for this kind of encapsulation, 455335640Shselasky * and will be handled as a pseudo header by the decoding application. 456335640Shselasky * The information carried in the ERF header and in the optional subheader (if present) 457335640Shselasky * could be merged with the libpcap information, to offer a better decoding. 458335640Shselasky * The packet length is 459335640Shselasky * o the length of the packet on the link (header->wlen), 460335640Shselasky * o plus the length of the ERF header (dag_record_size), as the length of the 461335640Shselasky * pseudo header will be adjusted during the decoding, 462335640Shselasky * o plus the length of the optional subheader (if present). 463335640Shselasky * 464335640Shselasky * The capture length is header.rlen and the byte stuffing for alignment will be dropped 465335640Shselasky * if the capture length is greater than the packet length. 466335640Shselasky */ 467335640Shselasky if (p->linktype == DLT_ERF) { 468335640Shselasky packet_len = ntohs(header->wlen) + dag_record_size; 469335640Shselasky caplen = rlen; 470335640Shselasky switch ((header->type & 0x7f)) { 471335640Shselasky case ERF_TYPE_MC_AAL5: 472335640Shselasky case ERF_TYPE_MC_ATM: 473335640Shselasky case ERF_TYPE_MC_HDLC: 474335640Shselasky case ERF_TYPE_MC_RAW_CHANNEL: 475335640Shselasky case ERF_TYPE_MC_RAW: 476335640Shselasky case ERF_TYPE_MC_AAL2: 477335640Shselasky case ERF_TYPE_COLOR_MC_HDLC_POS: 478335640Shselasky packet_len += 4; /* MC header */ 479335640Shselasky break; 480335640Shselasky 481335640Shselasky case ERF_TYPE_COLOR_HASH_ETH: 482335640Shselasky case ERF_TYPE_DSM_COLOR_ETH: 483335640Shselasky case ERF_TYPE_COLOR_ETH: 484335640Shselasky case ERF_TYPE_ETH: 485335640Shselasky packet_len += 2; /* ETH header */ 486335640Shselasky break; 487335640Shselasky } /* switch type */ 488335640Shselasky 489335640Shselasky /* Include ERF extension headers */ 490335640Shselasky packet_len += (8 * num_ext_hdr); 491335640Shselasky 492335640Shselasky if (caplen > packet_len) { 493335640Shselasky caplen = packet_len; 494335640Shselasky } 495335640Shselasky } else { 496335640Shselasky /* Other kind of encapsulation according to the header Type */ 497335640Shselasky 498335640Shselasky /* Skip over generic ERF header */ 499335640Shselasky dp += dag_record_size; 500335640Shselasky /* Skip over extension headers */ 501335640Shselasky dp += 8 * num_ext_hdr; 502335640Shselasky 503335640Shselasky switch((header->type & 0x7f)) { 504335640Shselasky case ERF_TYPE_ATM: 505335640Shselasky case ERF_TYPE_AAL5: 506335640Shselasky if ((header->type & 0x7f) == ERF_TYPE_AAL5) { 507335640Shselasky packet_len = ntohs(header->wlen); 508335640Shselasky caplen = rlen - dag_record_size; 509335640Shselasky } 510335640Shselasky case ERF_TYPE_MC_ATM: 511335640Shselasky if ((header->type & 0x7f) == ERF_TYPE_MC_ATM) { 512335640Shselasky caplen = packet_len = ATM_CELL_SIZE; 513335640Shselasky dp+=4; 514335640Shselasky } 515335640Shselasky case ERF_TYPE_MC_AAL5: 516335640Shselasky if ((header->type & 0x7f) == ERF_TYPE_MC_AAL5) { 517335640Shselasky packet_len = ntohs(header->wlen); 518335640Shselasky caplen = rlen - dag_record_size - 4; 519335640Shselasky dp+=4; 520335640Shselasky } 521335640Shselasky /* Skip over extension headers */ 522335640Shselasky caplen -= (8 * num_ext_hdr); 523335640Shselasky 524335640Shselasky if ((header->type & 0x7f) == ERF_TYPE_ATM) { 525335640Shselasky caplen = packet_len = ATM_CELL_SIZE; 526335640Shselasky } 527335640Shselasky if (p->linktype == DLT_SUNATM) { 528335640Shselasky struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; 529335640Shselasky unsigned long rawatm; 530335640Shselasky 531335640Shselasky rawatm = ntohl(*((unsigned long *)dp)); 532335640Shselasky sunatm->vci = htons((rawatm >> 4) & 0xffff); 533335640Shselasky sunatm->vpi = (rawatm >> 20) & 0x00ff; 534335640Shselasky sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | 535335640Shselasky ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : 536335640Shselasky ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : 537335640Shselasky ((dp[ATM_HDR_SIZE] == 0xaa && 538335640Shselasky dp[ATM_HDR_SIZE+1] == 0xaa && 539335640Shselasky dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); 540335640Shselasky 541335640Shselasky } else if (p->linktype == DLT_ATM_RFC1483) { 542335640Shselasky packet_len -= ATM_HDR_SIZE; 543335640Shselasky caplen -= ATM_HDR_SIZE; 544335640Shselasky dp += ATM_HDR_SIZE; 545335640Shselasky } else 546335640Shselasky continue; 547335640Shselasky break; 548335640Shselasky 549335640Shselasky case ERF_TYPE_COLOR_HASH_ETH: 550335640Shselasky case ERF_TYPE_DSM_COLOR_ETH: 551335640Shselasky case ERF_TYPE_COLOR_ETH: 552335640Shselasky case ERF_TYPE_ETH: 553335640Shselasky if ((p->linktype != DLT_EN10MB) && 554335640Shselasky (p->linktype != DLT_DOCSIS)) 555335640Shselasky continue; 556335640Shselasky packet_len = ntohs(header->wlen); 557335640Shselasky packet_len -= (pd->dag_fcs_bits >> 3); 558335640Shselasky caplen = rlen - dag_record_size - 2; 559335640Shselasky /* Skip over extension headers */ 560335640Shselasky caplen -= (8 * num_ext_hdr); 561335640Shselasky if (caplen > packet_len) { 562335640Shselasky caplen = packet_len; 563335640Shselasky } 564335640Shselasky dp += 2; 565335640Shselasky break; 566335640Shselasky 567335640Shselasky case ERF_TYPE_COLOR_HASH_POS: 568335640Shselasky case ERF_TYPE_DSM_COLOR_HDLC_POS: 569335640Shselasky case ERF_TYPE_COLOR_HDLC_POS: 570335640Shselasky case ERF_TYPE_HDLC_POS: 571335640Shselasky if ((p->linktype != DLT_CHDLC) && 572335640Shselasky (p->linktype != DLT_PPP_SERIAL) && 573335640Shselasky (p->linktype != DLT_FRELAY)) 574335640Shselasky continue; 575335640Shselasky packet_len = ntohs(header->wlen); 576335640Shselasky packet_len -= (pd->dag_fcs_bits >> 3); 577335640Shselasky caplen = rlen - dag_record_size; 578335640Shselasky /* Skip over extension headers */ 579335640Shselasky caplen -= (8 * num_ext_hdr); 580335640Shselasky if (caplen > packet_len) { 581335640Shselasky caplen = packet_len; 582335640Shselasky } 583335640Shselasky break; 584335640Shselasky 585335640Shselasky case ERF_TYPE_COLOR_MC_HDLC_POS: 586335640Shselasky case ERF_TYPE_MC_HDLC: 587335640Shselasky if ((p->linktype != DLT_CHDLC) && 588335640Shselasky (p->linktype != DLT_PPP_SERIAL) && 589335640Shselasky (p->linktype != DLT_FRELAY) && 590335640Shselasky (p->linktype != DLT_MTP2) && 591335640Shselasky (p->linktype != DLT_MTP2_WITH_PHDR) && 592335640Shselasky (p->linktype != DLT_LAPD)) 593335640Shselasky continue; 594335640Shselasky packet_len = ntohs(header->wlen); 595335640Shselasky packet_len -= (pd->dag_fcs_bits >> 3); 596335640Shselasky caplen = rlen - dag_record_size - 4; 597335640Shselasky /* Skip over extension headers */ 598335640Shselasky caplen -= (8 * num_ext_hdr); 599335640Shselasky if (caplen > packet_len) { 600335640Shselasky caplen = packet_len; 601335640Shselasky } 602335640Shselasky /* jump the MC_HDLC_HEADER */ 603335640Shselasky dp += 4; 604335640Shselasky#ifdef DLT_MTP2_WITH_PHDR 605335640Shselasky if (p->linktype == DLT_MTP2_WITH_PHDR) { 606335640Shselasky /* Add the MTP2 Pseudo Header */ 607335640Shselasky caplen += MTP2_HDR_LEN; 608335640Shselasky packet_len += MTP2_HDR_LEN; 609335640Shselasky 610335640Shselasky TempPkt[MTP2_SENT_OFFSET] = 0; 611335640Shselasky TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN; 612335640Shselasky *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01); 613335640Shselasky *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff); 614335640Shselasky memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen); 615335640Shselasky dp = TempPkt; 616335640Shselasky } 617335640Shselasky#endif 618335640Shselasky break; 619335640Shselasky 620335640Shselasky case ERF_TYPE_IPV4: 621335640Shselasky if ((p->linktype != DLT_RAW) && 622335640Shselasky (p->linktype != DLT_IPV4)) 623335640Shselasky continue; 624335640Shselasky packet_len = ntohs(header->wlen); 625335640Shselasky caplen = rlen - dag_record_size; 626335640Shselasky /* Skip over extension headers */ 627335640Shselasky caplen -= (8 * num_ext_hdr); 628335640Shselasky if (caplen > packet_len) { 629335640Shselasky caplen = packet_len; 630335640Shselasky } 631335640Shselasky break; 632335640Shselasky 633335640Shselasky case ERF_TYPE_IPV6: 634335640Shselasky if ((p->linktype != DLT_RAW) && 635335640Shselasky (p->linktype != DLT_IPV6)) 636335640Shselasky continue; 637335640Shselasky packet_len = ntohs(header->wlen); 638335640Shselasky caplen = rlen - dag_record_size; 639335640Shselasky /* Skip over extension headers */ 640335640Shselasky caplen -= (8 * num_ext_hdr); 641335640Shselasky if (caplen > packet_len) { 642335640Shselasky caplen = packet_len; 643335640Shselasky } 644335640Shselasky break; 645335640Shselasky 646335640Shselasky /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */ 647335640Shselasky case ERF_TYPE_MC_RAW: 648335640Shselasky case ERF_TYPE_MC_RAW_CHANNEL: 649335640Shselasky case ERF_TYPE_IP_COUNTER: 650335640Shselasky case ERF_TYPE_TCP_FLOW_COUNTER: 651335640Shselasky case ERF_TYPE_INFINIBAND: 652335640Shselasky case ERF_TYPE_RAW_LINK: 653335640Shselasky case ERF_TYPE_INFINIBAND_LINK: 654335640Shselasky default: 655335640Shselasky /* Unhandled ERF type. 656335640Shselasky * Ignore rather than generating error 657335640Shselasky */ 658335640Shselasky continue; 659335640Shselasky } /* switch type */ 660335640Shselasky 661335640Shselasky } /* ERF encapsulation */ 662335640Shselasky 663335640Shselasky if (caplen > p->snapshot) 664335640Shselasky caplen = p->snapshot; 665335640Shselasky 666335640Shselasky /* Run the packet filter if there is one. */ 667335640Shselasky if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { 668335640Shselasky 669335640Shselasky /* convert between timestamp formats */ 670335640Shselasky register unsigned long long ts; 671335640Shselasky 672335640Shselasky if (IS_BIGENDIAN()) { 673335640Shselasky ts = SWAPLL(header->ts); 674335640Shselasky } else { 675335640Shselasky ts = header->ts; 676335640Shselasky } 677335640Shselasky 678335640Shselasky switch (p->opt.tstamp_precision) { 679335640Shselasky case PCAP_TSTAMP_PRECISION_NANO: 680335640Shselasky ticks_per_second = 1000000000; 681335640Shselasky break; 682335640Shselasky case PCAP_TSTAMP_PRECISION_MICRO: 683335640Shselasky default: 684335640Shselasky ticks_per_second = 1000000; 685335640Shselasky break; 686335640Shselasky 687335640Shselasky } 688335640Shselasky pcap_header.ts.tv_sec = ts >> 32; 689335640Shselasky ts = (ts & 0xffffffffULL) * ticks_per_second; 690335640Shselasky ts += 0x80000000; /* rounding */ 691335640Shselasky pcap_header.ts.tv_usec = ts >> 32; 692335640Shselasky if (pcap_header.ts.tv_usec >= ticks_per_second) { 693335640Shselasky pcap_header.ts.tv_usec -= ticks_per_second; 694335640Shselasky pcap_header.ts.tv_sec++; 695335640Shselasky } 696335640Shselasky 697335640Shselasky /* Fill in our own header data */ 698335640Shselasky pcap_header.caplen = caplen; 699335640Shselasky pcap_header.len = packet_len; 700335640Shselasky 701335640Shselasky /* Count the packet. */ 702335640Shselasky pd->stat.ps_recv++; 703335640Shselasky 704335640Shselasky /* Call the user supplied callback function */ 705335640Shselasky callback(user, &pcap_header, dp); 706335640Shselasky 707335640Shselasky /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ 708335640Shselasky processed++; 709335640Shselasky if (processed == cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) 710335640Shselasky { 711335640Shselasky /* Reached the user-specified limit. */ 712335640Shselasky return cnt; 713335640Shselasky } 714335640Shselasky } 715335640Shselasky } 716335640Shselasky 717335640Shselasky return processed; 718335640Shselasky} 719335640Shselasky 720335640Shselaskystatic int 721335640Shselaskydag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) 722335640Shselasky{ 723356341Scy pcap_strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards", 724335640Shselasky PCAP_ERRBUF_SIZE); 725335640Shselasky return (-1); 726335640Shselasky} 727335640Shselasky 728335640Shselasky/* 729335640Shselasky * Get a handle for a live capture from the given DAG device. Passing a NULL 730335640Shselasky * device will result in a failure. The promisc flag is ignored because DAG 731335640Shselasky * cards are always promiscuous. The to_ms parameter is used in setting the 732335640Shselasky * API polling parameters. 733335640Shselasky * 734335640Shselasky * snaplen is now also ignored, until we get per-stream slen support. Set 735335640Shselasky * slen with approprite DAG tool BEFORE pcap_activate(). 736335640Shselasky * 737335640Shselasky * See also pcap(3). 738335640Shselasky */ 739335640Shselaskystatic int dag_activate(pcap_t* p) 740335640Shselasky{ 741335640Shselasky struct pcap_dag *pd = p->priv; 742335640Shselasky char *s; 743335640Shselasky int n; 744335640Shselasky daginf_t* daginf; 745335640Shselasky char * newDev = NULL; 746335640Shselasky char * device = p->opt.device; 747356341Scy int ret; 748335640Shselasky dag_size_t mindata; 749335640Shselasky struct timeval maxwait; 750335640Shselasky struct timeval poll; 751335640Shselasky 752335640Shselasky if (device == NULL) { 753335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL"); 754356341Scy return PCAP_ERROR; 755335640Shselasky } 756335640Shselasky 757335640Shselasky /* Initialize some components of the pcap structure. */ 758335640Shselasky newDev = (char *)malloc(strlen(device) + 16); 759335640Shselasky if (newDev == NULL) { 760356341Scy ret = PCAP_ERROR; 761335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 762335640Shselasky errno, "Can't allocate string for device name"); 763335640Shselasky goto fail; 764335640Shselasky } 765335640Shselasky 766335640Shselasky /* Parse input name to get dag device and stream number if provided */ 767335640Shselasky if (dag_parse_name(device, newDev, strlen(device) + 16, &pd->dag_stream) < 0) { 768356341Scy /* 769356341Scy * XXX - it'd be nice if this indicated what was wrong 770356341Scy * with the name. Does this reliably set errno? 771356341Scy * Should this return PCAP_ERROR_NO_SUCH_DEVICE in some 772356341Scy * cases? 773356341Scy */ 774356341Scy ret = PCAP_ERROR; 775335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 776335640Shselasky errno, "dag_parse_name"); 777335640Shselasky goto fail; 778335640Shselasky } 779335640Shselasky device = newDev; 780335640Shselasky 781335640Shselasky if (pd->dag_stream%2) { 782356341Scy ret = PCAP_ERROR; 783335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture"); 784335640Shselasky goto fail; 785335640Shselasky } 786335640Shselasky 787335640Shselasky /* setup device parameters */ 788335640Shselasky if((pd->dag_ref = dag_config_init((char *)device)) == NULL) { 789356341Scy /* 790356341Scy * XXX - does this reliably set errno? 791356341Scy */ 792356341Scy if (errno == ENOENT) 793356341Scy ret = PCAP_ERROR_NO_SUCH_DEVICE; 794356341Scy else if (errno == EPERM || errno == EACCES) 795356341Scy ret = PCAP_ERROR_PERM_DENIED; 796356341Scy else 797356341Scy ret = PCAP_ERROR; 798335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 799335640Shselasky errno, "dag_config_init %s", device); 800335640Shselasky goto fail; 801335640Shselasky } 802335640Shselasky 803335640Shselasky if((p->fd = dag_config_get_card_fd(pd->dag_ref)) < 0) { 804356341Scy /* 805356341Scy * XXX - does this reliably set errno? 806356341Scy */ 807356341Scy ret = PCAP_ERROR; 808335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 809335640Shselasky errno, "dag_config_get_card_fd %s", device); 810356341Scy goto failclose; 811335640Shselasky } 812335640Shselasky 813335640Shselasky /* Open requested stream. Can fail if already locked or on error */ 814335640Shselasky if (dag_attach_stream64(p->fd, pd->dag_stream, 0, 0) < 0) { 815356341Scy ret = PCAP_ERROR; 816335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 817335640Shselasky errno, "dag_attach_stream"); 818335640Shselasky goto failclose; 819335640Shselasky } 820335640Shselasky 821335640Shselasky /* Try to find Stream Drop attribute */ 822335640Shselasky pd->drop_attr = kNullAttributeUuid; 823335640Shselasky pd->dag_root = dag_config_get_root_component(pd->dag_ref); 824335640Shselasky if ( dag_component_get_subcomponent(pd->dag_root, kComponentStreamFeatures, 0) ) 825335640Shselasky { 826335640Shselasky pd->drop_attr = dag_config_get_indexed_attribute_uuid(pd->dag_ref, kUint32AttributeStreamDropCount, pd->dag_stream/2); 827335640Shselasky } 828335640Shselasky 829335640Shselasky /* Set up default poll parameters for stream 830335640Shselasky * Can be overridden by pcap_set_nonblock() 831335640Shselasky */ 832335640Shselasky if (dag_get_stream_poll64(p->fd, pd->dag_stream, 833335640Shselasky &mindata, &maxwait, &poll) < 0) { 834356341Scy ret = PCAP_ERROR; 835335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 836335640Shselasky errno, "dag_get_stream_poll"); 837335640Shselasky goto faildetach; 838335640Shselasky } 839335640Shselasky 840335640Shselasky /* Use the poll time as the required select timeout for callers 841335640Shselasky * who are using select()/etc. in an event loop waiting for 842335640Shselasky * packets to arrive. 843335640Shselasky */ 844335640Shselasky pd->required_select_timeout = poll; 845335640Shselasky p->required_select_timeout = &pd->required_select_timeout; 846335640Shselasky 847335640Shselasky /* 848335640Shselasky * Turn a negative snapshot value (invalid), a snapshot value of 849335640Shselasky * 0 (unspecified), or a value bigger than the normal maximum 850335640Shselasky * value, into the maximum allowed value. 851335640Shselasky * 852335640Shselasky * If some application really *needs* a bigger snapshot 853335640Shselasky * length, we should just increase MAXIMUM_SNAPLEN. 854335640Shselasky */ 855335640Shselasky if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) 856335640Shselasky p->snapshot = MAXIMUM_SNAPLEN; 857335640Shselasky 858335640Shselasky if (p->opt.immediate) { 859335640Shselasky /* Call callback immediately. 860335640Shselasky * XXX - is this the right way to p this? 861335640Shselasky */ 862335640Shselasky mindata = 0; 863335640Shselasky } else { 864335640Shselasky /* Amount of data to collect in Bytes before calling callbacks. 865335640Shselasky * Important for efficiency, but can introduce latency 866335640Shselasky * at low packet rates if to_ms not set! 867335640Shselasky */ 868335640Shselasky mindata = 65536; 869335640Shselasky } 870335640Shselasky 871335640Shselasky /* Obey opt.timeout (was to_ms) if supplied. This is a good idea! 872335640Shselasky * Recommend 10-100ms. Calls will time out even if no data arrived. 873335640Shselasky */ 874335640Shselasky maxwait.tv_sec = p->opt.timeout/1000; 875335640Shselasky maxwait.tv_usec = (p->opt.timeout%1000) * 1000; 876335640Shselasky 877335640Shselasky if (dag_set_stream_poll64(p->fd, pd->dag_stream, 878335640Shselasky mindata, &maxwait, &poll) < 0) { 879356341Scy ret = PCAP_ERROR; 880335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 881335640Shselasky errno, "dag_set_stream_poll"); 882335640Shselasky goto faildetach; 883335640Shselasky } 884335640Shselasky 885335640Shselasky /* XXX Not calling dag_configure() to set slen; this is unsafe in 886335640Shselasky * multi-stream environments as the gpp config is global. 887335640Shselasky * Once the firmware provides 'per-stream slen' this can be supported 888335640Shselasky * again via the Config API without side-effects */ 889335640Shselasky#if 0 890335640Shselasky /* set the card snap length to the specified snaplen parameter */ 891335640Shselasky /* This is a really bad idea, as different cards have different 892335640Shselasky * valid slen ranges. Should fix in Config API. */ 893335640Shselasky if (p->snapshot == 0 || p->snapshot > MAX_DAG_SNAPLEN) { 894335640Shselasky p->snapshot = MAX_DAG_SNAPLEN; 895335640Shselasky } else if (snaplen < MIN_DAG_SNAPLEN) { 896335640Shselasky p->snapshot = MIN_DAG_SNAPLEN; 897335640Shselasky } 898335640Shselasky /* snap len has to be a multiple of 4 */ 899335640Shselasky#endif 900335640Shselasky 901335640Shselasky if(dag_start_stream(p->fd, pd->dag_stream) < 0) { 902356341Scy ret = PCAP_ERROR; 903335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 904335640Shselasky errno, "dag_start_stream %s", device); 905335640Shselasky goto faildetach; 906335640Shselasky } 907335640Shselasky 908335640Shselasky /* 909335640Shselasky * Important! You have to ensure bottom is properly 910335640Shselasky * initialized to zero on startup, it won't give you 911335640Shselasky * a compiler warning if you make this mistake! 912335640Shselasky */ 913335640Shselasky pd->dag_mem_bottom = 0; 914335640Shselasky pd->dag_mem_top = 0; 915335640Shselasky 916335640Shselasky /* 917335640Shselasky * Find out how many FCS bits we should strip. 918335640Shselasky * First, query the card to see if it strips the FCS. 919335640Shselasky */ 920335640Shselasky daginf = dag_info(p->fd); 921335640Shselasky if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) { 922335640Shselasky /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */ 923335640Shselasky pd->dag_fcs_bits = 0; 924335640Shselasky 925335640Shselasky /* Note that no FCS will be supplied. */ 926335640Shselasky p->linktype_ext = LT_FCS_DATALINK_EXT(0); 927335640Shselasky } else { 928335640Shselasky /* 929335640Shselasky * Start out assuming it's 32 bits. 930335640Shselasky */ 931335640Shselasky pd->dag_fcs_bits = 32; 932335640Shselasky 933335640Shselasky /* Allow an environment variable to override. */ 934335640Shselasky if ((s = getenv("ERF_FCS_BITS")) != NULL) { 935335640Shselasky if ((n = atoi(s)) == 0 || n == 16 || n == 32) { 936335640Shselasky pd->dag_fcs_bits = n; 937335640Shselasky } else { 938356341Scy ret = PCAP_ERROR; 939335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, 940335640Shselasky "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment", device, n); 941335640Shselasky goto failstop; 942335640Shselasky } 943335640Shselasky } 944335640Shselasky 945335640Shselasky /* 946335640Shselasky * Did the user request that they not be stripped? 947335640Shselasky */ 948335640Shselasky if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) { 949335640Shselasky /* Yes. Note the number of bytes that will be 950335640Shselasky supplied. */ 951335640Shselasky p->linktype_ext = LT_FCS_DATALINK_EXT(pd->dag_fcs_bits/16); 952335640Shselasky 953335640Shselasky /* And don't strip them. */ 954335640Shselasky pd->dag_fcs_bits = 0; 955335640Shselasky } 956335640Shselasky } 957335640Shselasky 958335640Shselasky pd->dag_timeout = p->opt.timeout; 959335640Shselasky 960335640Shselasky p->linktype = -1; 961356341Scy if (dag_get_datalink(p) < 0) { 962356341Scy ret = PCAP_ERROR; 963335640Shselasky goto failstop; 964356341Scy } 965335640Shselasky 966335640Shselasky p->bufsize = 0; 967335640Shselasky 968335640Shselasky if (new_pcap_dag(p) < 0) { 969356341Scy ret = PCAP_ERROR; 970335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 971335640Shselasky errno, "new_pcap_dag %s", device); 972335640Shselasky goto failstop; 973335640Shselasky } 974335640Shselasky 975335640Shselasky /* 976335640Shselasky * "select()" and "poll()" don't work on DAG device descriptors. 977335640Shselasky */ 978335640Shselasky p->selectable_fd = -1; 979335640Shselasky 980335640Shselasky if (newDev != NULL) { 981335640Shselasky free((char *)newDev); 982335640Shselasky } 983335640Shselasky 984335640Shselasky p->read_op = dag_read; 985335640Shselasky p->inject_op = dag_inject; 986335640Shselasky p->setfilter_op = dag_setfilter; 987335640Shselasky p->setdirection_op = NULL; /* Not implemented.*/ 988335640Shselasky p->set_datalink_op = dag_set_datalink; 989335640Shselasky p->getnonblock_op = pcap_getnonblock_fd; 990335640Shselasky p->setnonblock_op = dag_setnonblock; 991335640Shselasky p->stats_op = dag_stats; 992335640Shselasky p->cleanup_op = dag_platform_cleanup; 993335640Shselasky pd->stat.ps_drop = 0; 994335640Shselasky pd->stat.ps_recv = 0; 995335640Shselasky pd->stat.ps_ifdrop = 0; 996335640Shselasky return 0; 997335640Shselasky 998335640Shselaskyfailstop: 999335640Shselasky if (dag_stop_stream(p->fd, pd->dag_stream) < 0) { 1000335640Shselasky fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); 1001335640Shselasky } 1002335640Shselasky 1003335640Shselaskyfaildetach: 1004335640Shselasky if (dag_detach_stream(p->fd, pd->dag_stream) < 0) 1005335640Shselasky fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); 1006335640Shselasky 1007335640Shselaskyfailclose: 1008335640Shselasky dag_config_dispose(pd->dag_ref); 1009356341Scy /* 1010356341Scy * Note: we don't need to call close(p->fd) or dag_close(p->fd), 1011356341Scy * as dag_config_dispose(pd->dag_ref) does this. 1012356341Scy * 1013356341Scy * Set p->fd to -1 to make sure that's not done. 1014356341Scy */ 1015356341Scy p->fd = -1; 1016356341Scy pd->dag_ref = NULL; 1017335640Shselasky delete_pcap_dag(p); 1018335640Shselasky 1019335640Shselaskyfail: 1020335640Shselasky pcap_cleanup_live_common(p); 1021335640Shselasky if (newDev != NULL) { 1022335640Shselasky free((char *)newDev); 1023335640Shselasky } 1024335640Shselasky 1025356341Scy return ret; 1026335640Shselasky} 1027335640Shselasky 1028335640Shselaskypcap_t *dag_create(const char *device, char *ebuf, int *is_ours) 1029335640Shselasky{ 1030335640Shselasky const char *cp; 1031335640Shselasky char *cpend; 1032335640Shselasky long devnum; 1033335640Shselasky pcap_t *p; 1034335640Shselasky long stream = 0; 1035335640Shselasky 1036335640Shselasky /* Does this look like a DAG device? */ 1037335640Shselasky cp = strrchr(device, '/'); 1038335640Shselasky if (cp == NULL) 1039335640Shselasky cp = device; 1040335640Shselasky /* Does it begin with "dag"? */ 1041335640Shselasky if (strncmp(cp, "dag", 3) != 0) { 1042335640Shselasky /* Nope, doesn't begin with "dag" */ 1043335640Shselasky *is_ours = 0; 1044335640Shselasky return NULL; 1045335640Shselasky } 1046335640Shselasky /* Yes - is "dag" followed by a number from 0 to DAG_MAX_BOARDS-1 */ 1047335640Shselasky cp += 3; 1048335640Shselasky devnum = strtol(cp, &cpend, 10); 1049335640Shselasky if (*cpend == ':') { 1050335640Shselasky /* Followed by a stream number. */ 1051335640Shselasky stream = strtol(++cpend, &cpend, 10); 1052335640Shselasky } 1053335640Shselasky 1054335640Shselasky if (cpend == cp || *cpend != '\0') { 1055335640Shselasky /* Not followed by a number. */ 1056335640Shselasky *is_ours = 0; 1057335640Shselasky return NULL; 1058335640Shselasky } 1059335640Shselasky 1060335640Shselasky if (devnum < 0 || devnum >= DAG_MAX_BOARDS) { 1061335640Shselasky /* Followed by a non-valid number. */ 1062335640Shselasky *is_ours = 0; 1063335640Shselasky return NULL; 1064335640Shselasky } 1065335640Shselasky 1066335640Shselasky if (stream <0 || stream >= DAG_STREAM_MAX) { 1067335640Shselasky /* Followed by a non-valid stream number. */ 1068335640Shselasky *is_ours = 0; 1069335640Shselasky return NULL; 1070335640Shselasky } 1071335640Shselasky 1072335640Shselasky /* OK, it's probably ours. */ 1073335640Shselasky *is_ours = 1; 1074335640Shselasky 1075335640Shselasky p = pcap_create_common(ebuf, sizeof (struct pcap_dag)); 1076335640Shselasky if (p == NULL) 1077335640Shselasky return NULL; 1078335640Shselasky 1079335640Shselasky p->activate_op = dag_activate; 1080335640Shselasky 1081335640Shselasky /* 1082335640Shselasky * We claim that we support microsecond and nanosecond time 1083335640Shselasky * stamps. 1084335640Shselasky * 1085335640Shselasky * XXX Our native precision is 2^-32s, but libpcap doesn't support 1086335640Shselasky * power of two precisions yet. We can convert to either MICRO or NANO. 1087335640Shselasky */ 1088335640Shselasky p->tstamp_precision_count = 2; 1089335640Shselasky p->tstamp_precision_list = malloc(2 * sizeof(u_int)); 1090335640Shselasky if (p->tstamp_precision_list == NULL) { 1091335640Shselasky pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE, 1092335640Shselasky errno, "malloc"); 1093335640Shselasky pcap_close(p); 1094335640Shselasky return NULL; 1095335640Shselasky } 1096335640Shselasky p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; 1097335640Shselasky p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; 1098335640Shselasky return p; 1099335640Shselasky} 1100335640Shselasky 1101335640Shselaskystatic int 1102335640Shselaskydag_stats(pcap_t *p, struct pcap_stat *ps) { 1103335640Shselasky struct pcap_dag *pd = p->priv; 1104335640Shselasky uint32_t stream_drop; 1105335640Shselasky dag_err_t dag_error; 1106335640Shselasky 1107335640Shselasky /* 1108335640Shselasky * Packet records received (ps_recv) are counted in dag_read(). 1109335640Shselasky * Packet records dropped (ps_drop) are read from Stream Drop attribute if present, 1110335640Shselasky * otherwise integrate the ERF Header lctr counts (if available) in dag_read(). 1111335640Shselasky * We are reporting that no records are dropped by the card/driver (ps_ifdrop). 1112335640Shselasky */ 1113335640Shselasky 1114335640Shselasky if(pd->drop_attr != kNullAttributeUuid) { 1115335640Shselasky /* Note this counter is cleared at start of capture and will wrap at UINT_MAX. 1116335640Shselasky * The application is responsible for polling ps_drop frequently enough 1117335640Shselasky * to detect each wrap and integrate total drop with a wider counter */ 1118335640Shselasky if ((dag_error = dag_config_get_uint32_attribute_ex(pd->dag_ref, pd->drop_attr, &stream_drop) == kDagErrNone)) { 1119335640Shselasky pd->stat.ps_drop = stream_drop; 1120335640Shselasky } else { 1121335640Shselasky pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "reading stream drop attribute: %s", 1122335640Shselasky dag_config_strerror(dag_error)); 1123335640Shselasky return -1; 1124335640Shselasky } 1125335640Shselasky } 1126335640Shselasky 1127335640Shselasky *ps = pd->stat; 1128335640Shselasky 1129335640Shselasky return 0; 1130335640Shselasky} 1131335640Shselasky 1132335640Shselasky/* 1133335640Shselasky * Add all DAG devices. 1134335640Shselasky */ 1135335640Shselaskyint 1136335640Shselaskydag_findalldevs(pcap_if_list_t *devlistp, char *errbuf) 1137335640Shselasky{ 1138335640Shselasky char name[12]; /* XXX - pick a size */ 1139335640Shselasky int c; 1140335640Shselasky char dagname[DAGNAME_BUFSIZE]; 1141335640Shselasky int dagstream; 1142335640Shselasky int dagfd; 1143335640Shselasky dag_card_inf_t *inf; 1144335640Shselasky char *description; 1145335640Shselasky int stream, rxstreams; 1146335640Shselasky 1147335640Shselasky /* Try all the DAGs 0-DAG_MAX_BOARDS */ 1148335640Shselasky for (c = 0; c < DAG_MAX_BOARDS; c++) { 1149335640Shselasky pcap_snprintf(name, 12, "dag%d", c); 1150335640Shselasky if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream)) 1151335640Shselasky { 1152335640Shselasky (void) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 1153335640Shselasky "dag: device name %s can't be parsed", name); 1154335640Shselasky return (-1); 1155335640Shselasky } 1156335640Shselasky if ( (dagfd = dag_open(dagname)) >= 0 ) { 1157335640Shselasky description = NULL; 1158335640Shselasky if ((inf = dag_pciinfo(dagfd))) 1159335640Shselasky description = dag_device_name(inf->device_code, 1); 1160335640Shselasky /* 1161335640Shselasky * XXX - is there a way to determine whether 1162335640Shselasky * the card is plugged into a network or not? 1163335640Shselasky * If so, we should check that and set 1164335640Shselasky * PCAP_IF_CONNECTION_STATUS_CONNECTED or 1165335640Shselasky * PCAP_IF_CONNECTION_STATUS_DISCONNECTED. 1166335640Shselasky * 1167335640Shselasky * Also, are there notions of "up" and "running"? 1168335640Shselasky */ 1169335640Shselasky if (add_dev(devlistp, name, 0, description, errbuf) == NULL) { 1170335640Shselasky /* 1171335640Shselasky * Failure. 1172335640Shselasky */ 1173335640Shselasky return (-1); 1174335640Shselasky } 1175335640Shselasky rxstreams = dag_rx_get_stream_count(dagfd); 1176335640Shselasky for(stream=0;stream<DAG_STREAM_MAX;stream+=2) { 1177356341Scy if (0 == dag_attach_stream64(dagfd, stream, 0, 0)) { 1178335640Shselasky dag_detach_stream(dagfd, stream); 1179335640Shselasky 1180335640Shselasky pcap_snprintf(name, 10, "dag%d:%d", c, stream); 1181335640Shselasky if (add_dev(devlistp, name, 0, description, errbuf) == NULL) { 1182335640Shselasky /* 1183335640Shselasky * Failure. 1184335640Shselasky */ 1185335640Shselasky return (-1); 1186335640Shselasky } 1187335640Shselasky 1188335640Shselasky rxstreams--; 1189335640Shselasky if(rxstreams <= 0) { 1190335640Shselasky break; 1191335640Shselasky } 1192335640Shselasky } 1193335640Shselasky } 1194335640Shselasky dag_close(dagfd); 1195335640Shselasky } 1196335640Shselasky 1197335640Shselasky } 1198335640Shselasky return (0); 1199335640Shselasky} 1200335640Shselasky 1201335640Shselasky/* 1202335640Shselasky * Installs the given bpf filter program in the given pcap structure. There is 1203335640Shselasky * no attempt to store the filter in kernel memory as that is not supported 1204335640Shselasky * with DAG cards. 1205335640Shselasky */ 1206335640Shselaskystatic int 1207335640Shselaskydag_setfilter(pcap_t *p, struct bpf_program *fp) 1208335640Shselasky{ 1209335640Shselasky if (!p) 1210335640Shselasky return -1; 1211335640Shselasky if (!fp) { 1212335640Shselasky strncpy(p->errbuf, "setfilter: No filter specified", 1213335640Shselasky sizeof(p->errbuf)); 1214335640Shselasky return -1; 1215335640Shselasky } 1216335640Shselasky 1217335640Shselasky /* Make our private copy of the filter */ 1218335640Shselasky 1219335640Shselasky if (install_bpf_program(p, fp) < 0) 1220335640Shselasky return -1; 1221335640Shselasky 1222335640Shselasky return (0); 1223335640Shselasky} 1224335640Shselasky 1225335640Shselaskystatic int 1226335640Shselaskydag_set_datalink(pcap_t *p, int dlt) 1227335640Shselasky{ 1228335640Shselasky p->linktype = dlt; 1229335640Shselasky 1230335640Shselasky return (0); 1231335640Shselasky} 1232335640Shselasky 1233335640Shselaskystatic int 1234335640Shselaskydag_setnonblock(pcap_t *p, int nonblock) 1235335640Shselasky{ 1236335640Shselasky struct pcap_dag *pd = p->priv; 1237335640Shselasky dag_size_t mindata; 1238335640Shselasky struct timeval maxwait; 1239335640Shselasky struct timeval poll; 1240335640Shselasky 1241335640Shselasky /* 1242335640Shselasky * Set non-blocking mode on the FD. 1243335640Shselasky * XXX - is that necessary? If not, don't bother calling it, 1244335640Shselasky * and have a "dag_getnonblock()" function that looks at 1245335640Shselasky * "pd->dag_flags". 1246335640Shselasky */ 1247335640Shselasky if (pcap_setnonblock_fd(p, nonblock) < 0) 1248335640Shselasky return (-1); 1249335640Shselasky 1250335640Shselasky if (dag_get_stream_poll64(p->fd, pd->dag_stream, 1251335640Shselasky &mindata, &maxwait, &poll) < 0) { 1252335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 1253335640Shselasky errno, "dag_get_stream_poll"); 1254335640Shselasky return -1; 1255335640Shselasky } 1256335640Shselasky 1257335640Shselasky /* Amount of data to collect in Bytes before calling callbacks. 1258335640Shselasky * Important for efficiency, but can introduce latency 1259335640Shselasky * at low packet rates if to_ms not set! 1260335640Shselasky */ 1261335640Shselasky if(nonblock) 1262335640Shselasky mindata = 0; 1263335640Shselasky else 1264335640Shselasky mindata = 65536; 1265335640Shselasky 1266335640Shselasky if (dag_set_stream_poll64(p->fd, pd->dag_stream, 1267335640Shselasky mindata, &maxwait, &poll) < 0) { 1268335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 1269335640Shselasky errno, "dag_set_stream_poll"); 1270335640Shselasky return -1; 1271335640Shselasky } 1272335640Shselasky 1273335640Shselasky if (nonblock) { 1274335640Shselasky pd->dag_flags |= DAGF_NONBLOCK; 1275335640Shselasky } else { 1276335640Shselasky pd->dag_flags &= ~DAGF_NONBLOCK; 1277335640Shselasky } 1278335640Shselasky return (0); 1279335640Shselasky} 1280335640Shselasky 1281335640Shselaskystatic int 1282335640Shselaskydag_get_datalink(pcap_t *p) 1283335640Shselasky{ 1284335640Shselasky struct pcap_dag *pd = p->priv; 1285335640Shselasky int index=0, dlt_index=0; 1286335640Shselasky uint8_t types[255]; 1287335640Shselasky 1288335640Shselasky memset(types, 0, 255); 1289335640Shselasky 1290335640Shselasky if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) { 1291335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), 1292335640Shselasky errno, "malloc"); 1293335640Shselasky return (-1); 1294335640Shselasky } 1295335640Shselasky 1296335640Shselasky p->linktype = 0; 1297335640Shselasky 1298335640Shselasky#ifdef HAVE_DAG_GET_STREAM_ERF_TYPES 1299335640Shselasky /* Get list of possible ERF types for this card */ 1300335640Shselasky if (dag_get_stream_erf_types(p->fd, pd->dag_stream, types, 255) < 0) { 1301335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), 1302335640Shselasky errno, "dag_get_stream_erf_types"); 1303335640Shselasky return (-1); 1304335640Shselasky } 1305335640Shselasky 1306335640Shselasky while (types[index]) { 1307335640Shselasky 1308335640Shselasky#elif defined HAVE_DAG_GET_ERF_TYPES 1309335640Shselasky /* Get list of possible ERF types for this card */ 1310335640Shselasky if (dag_get_erf_types(p->fd, types, 255) < 0) { 1311335640Shselasky pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf), 1312335640Shselasky errno, "dag_get_erf_types"); 1313335640Shselasky return (-1); 1314335640Shselasky } 1315335640Shselasky 1316335640Shselasky while (types[index]) { 1317335640Shselasky#else 1318335640Shselasky /* Check the type through a dagapi call. */ 1319335640Shselasky types[index] = dag_linktype(p->fd); 1320335640Shselasky 1321335640Shselasky { 1322335640Shselasky#endif 1323335640Shselasky switch((types[index] & 0x7f)) { 1324335640Shselasky 1325335640Shselasky case ERF_TYPE_HDLC_POS: 1326335640Shselasky case ERF_TYPE_COLOR_HDLC_POS: 1327335640Shselasky case ERF_TYPE_DSM_COLOR_HDLC_POS: 1328335640Shselasky case ERF_TYPE_COLOR_HASH_POS: 1329335640Shselasky 1330335640Shselasky if (p->dlt_list != NULL) { 1331335640Shselasky p->dlt_list[dlt_index++] = DLT_CHDLC; 1332335640Shselasky p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; 1333335640Shselasky p->dlt_list[dlt_index++] = DLT_FRELAY; 1334335640Shselasky } 1335335640Shselasky if(!p->linktype) 1336335640Shselasky p->linktype = DLT_CHDLC; 1337335640Shselasky break; 1338335640Shselasky 1339335640Shselasky case ERF_TYPE_ETH: 1340335640Shselasky case ERF_TYPE_COLOR_ETH: 1341335640Shselasky case ERF_TYPE_DSM_COLOR_ETH: 1342335640Shselasky case ERF_TYPE_COLOR_HASH_ETH: 1343335640Shselasky /* 1344335640Shselasky * This is (presumably) a real Ethernet capture; give it a 1345335640Shselasky * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 1346335640Shselasky * that an application can let you choose it, in case you're 1347335640Shselasky * capturing DOCSIS traffic that a Cisco Cable Modem 1348335640Shselasky * Termination System is putting out onto an Ethernet (it 1349335640Shselasky * doesn't put an Ethernet header onto the wire, it puts raw 1350335640Shselasky * DOCSIS frames out on the wire inside the low-level 1351335640Shselasky * Ethernet framing). 1352335640Shselasky */ 1353335640Shselasky if (p->dlt_list != NULL) { 1354335640Shselasky p->dlt_list[dlt_index++] = DLT_EN10MB; 1355335640Shselasky p->dlt_list[dlt_index++] = DLT_DOCSIS; 1356335640Shselasky } 1357335640Shselasky if(!p->linktype) 1358335640Shselasky p->linktype = DLT_EN10MB; 1359335640Shselasky break; 1360335640Shselasky 1361335640Shselasky case ERF_TYPE_ATM: 1362335640Shselasky case ERF_TYPE_AAL5: 1363335640Shselasky case ERF_TYPE_MC_ATM: 1364335640Shselasky case ERF_TYPE_MC_AAL5: 1365335640Shselasky if (p->dlt_list != NULL) { 1366335640Shselasky p->dlt_list[dlt_index++] = DLT_ATM_RFC1483; 1367335640Shselasky p->dlt_list[dlt_index++] = DLT_SUNATM; 1368335640Shselasky } 1369335640Shselasky if(!p->linktype) 1370335640Shselasky p->linktype = DLT_ATM_RFC1483; 1371335640Shselasky break; 1372335640Shselasky 1373335640Shselasky case ERF_TYPE_COLOR_MC_HDLC_POS: 1374335640Shselasky case ERF_TYPE_MC_HDLC: 1375335640Shselasky if (p->dlt_list != NULL) { 1376335640Shselasky p->dlt_list[dlt_index++] = DLT_CHDLC; 1377335640Shselasky p->dlt_list[dlt_index++] = DLT_PPP_SERIAL; 1378335640Shselasky p->dlt_list[dlt_index++] = DLT_FRELAY; 1379335640Shselasky p->dlt_list[dlt_index++] = DLT_MTP2; 1380335640Shselasky p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR; 1381335640Shselasky p->dlt_list[dlt_index++] = DLT_LAPD; 1382335640Shselasky } 1383335640Shselasky if(!p->linktype) 1384335640Shselasky p->linktype = DLT_CHDLC; 1385335640Shselasky break; 1386335640Shselasky 1387335640Shselasky case ERF_TYPE_IPV4: 1388335640Shselasky if (p->dlt_list != NULL) { 1389335640Shselasky p->dlt_list[dlt_index++] = DLT_RAW; 1390335640Shselasky p->dlt_list[dlt_index++] = DLT_IPV4; 1391335640Shselasky } 1392335640Shselasky if(!p->linktype) 1393335640Shselasky p->linktype = DLT_RAW; 1394335640Shselasky break; 1395335640Shselasky 1396335640Shselasky case ERF_TYPE_IPV6: 1397335640Shselasky if (p->dlt_list != NULL) { 1398335640Shselasky p->dlt_list[dlt_index++] = DLT_RAW; 1399335640Shselasky p->dlt_list[dlt_index++] = DLT_IPV6; 1400335640Shselasky } 1401335640Shselasky if(!p->linktype) 1402335640Shselasky p->linktype = DLT_RAW; 1403335640Shselasky break; 1404335640Shselasky 1405335640Shselasky case ERF_TYPE_LEGACY: 1406335640Shselasky case ERF_TYPE_MC_RAW: 1407335640Shselasky case ERF_TYPE_MC_RAW_CHANNEL: 1408335640Shselasky case ERF_TYPE_IP_COUNTER: 1409335640Shselasky case ERF_TYPE_TCP_FLOW_COUNTER: 1410335640Shselasky case ERF_TYPE_INFINIBAND: 1411335640Shselasky case ERF_TYPE_RAW_LINK: 1412335640Shselasky case ERF_TYPE_INFINIBAND_LINK: 1413335640Shselasky case ERF_TYPE_META: 1414335640Shselasky default: 1415335640Shselasky /* Libpcap cannot deal with these types yet */ 1416335640Shselasky /* Add no 'native' DLTs, but still covered by DLT_ERF */ 1417335640Shselasky break; 1418335640Shselasky 1419335640Shselasky } /* switch */ 1420335640Shselasky index++; 1421335640Shselasky } 1422335640Shselasky 1423335640Shselasky p->dlt_list[dlt_index++] = DLT_ERF; 1424335640Shselasky 1425335640Shselasky p->dlt_count = dlt_index; 1426335640Shselasky 1427335640Shselasky if(!p->linktype) 1428335640Shselasky p->linktype = DLT_ERF; 1429335640Shselasky 1430335640Shselasky return p->linktype; 1431335640Shselasky} 1432335640Shselasky 1433335640Shselasky#ifdef DAG_ONLY 1434335640Shselasky/* 1435335640Shselasky * This libpcap build supports only DAG cards, not regular network 1436335640Shselasky * interfaces. 1437335640Shselasky */ 1438335640Shselasky 1439335640Shselasky/* 1440335640Shselasky * There are no regular interfaces, just DAG interfaces. 1441335640Shselasky */ 1442335640Shselaskyint 1443335640Shselaskypcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf) 1444335640Shselasky{ 1445335640Shselasky return (0); 1446335640Shselasky} 1447335640Shselasky 1448335640Shselasky/* 1449335640Shselasky * Attempts to open a regular interface fail. 1450335640Shselasky */ 1451335640Shselaskypcap_t * 1452335640Shselaskypcap_create_interface(const char *device, char *errbuf) 1453335640Shselasky{ 1454335640Shselasky pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, 1455335640Shselasky "This version of libpcap only supports DAG cards"); 1456335640Shselasky return NULL; 1457335640Shselasky} 1458335640Shselasky 1459335640Shselasky/* 1460335640Shselasky * Libpcap version string. 1461335640Shselasky */ 1462335640Shselaskyconst char * 1463335640Shselaskypcap_lib_version(void) 1464335640Shselasky{ 1465335640Shselasky return (PCAP_VERSION_STRING " (DAG-only)"); 1466335640Shselasky} 1467335640Shselasky#endif 1468