blob: 491524893e7af9881dbcf0367364c52f48a4fce7 [file] [log] [blame]
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001/*
Elliott Hughesd8845d72015-10-19 18:07:04 -07002 * pcap-dag.c: Packet capture interface for Emulex EndaceDAG cards.
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08003 *
4 * The functionality of this code attempts to mimic that of pcap-linux as much
5 * as possible. This code is compiled in several different ways depending on
6 * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not
7 * defined it should not get compiled in, otherwise if DAG_ONLY is defined then
8 * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY
9 * is not defined then nothing is altered - the dag_ functions will be
10 * called as required from their pcap-linux/bpf equivalents.
11 *
12 * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com)
Elliott Hughesd8845d72015-10-19 18:07:04 -070013 * Modifications: Jesper Peterson
14 * Koryn Grant
15 * Stephen Donnelly <stephen.donnelly@emulex.com>
The Android Open Source Project478ab6c2009-03-03 19:30:05 -080016 */
17
The Android Open Source Project478ab6c2009-03-03 19:30:05 -080018#ifdef HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <sys/param.h> /* optionally get BSD define */
23
24#include <stdlib.h>
25#include <string.h>
26#include <errno.h>
27
28#include "pcap-int.h"
29
30#include <ctype.h>
31#include <netinet/in.h>
32#include <sys/mman.h>
33#include <sys/socket.h>
34#include <sys/types.h>
35#include <unistd.h>
36
37struct mbuf; /* Squelch compiler warnings on some platforms for */
38struct rtentry; /* declarations in <net/if.h> */
39#include <net/if.h>
40
41#include "dagnew.h"
42#include "dagapi.h"
Elliott Hughesd8845d72015-10-19 18:07:04 -070043#include "dagpci.h"
The Android Open Source Project478ab6c2009-03-03 19:30:05 -080044
JP Abgrall511eca32014-02-12 13:46:45 -080045#include "pcap-dag.h"
46
47/*
48 * DAG devices have names beginning with "dag", followed by a number
49 * from 0 to DAG_MAX_BOARDS, then optionally a colon and a stream number
50 * from 0 to DAG_STREAM_MAX.
51 */
52#ifndef DAG_MAX_BOARDS
53#define DAG_MAX_BOARDS 32
54#endif
55
The Android Open Source Project478ab6c2009-03-03 19:30:05 -080056#define ATM_CELL_SIZE 52
57#define ATM_HDR_SIZE 4
58
59/*
60 * A header containing additional MTP information.
61 */
62#define MTP2_SENT_OFFSET 0 /* 1 byte */
63#define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */
64#define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */
65#define MTP2_HDR_LEN 4 /* length of the header */
66
67#define MTP2_ANNEX_A_NOT_USED 0
68#define MTP2_ANNEX_A_USED 1
69#define MTP2_ANNEX_A_USED_UNKNOWN 2
70
71/* SunATM pseudo header */
72struct sunatm_hdr {
73 unsigned char flags; /* destination and traffic type */
74 unsigned char vpi; /* VPI */
75 unsigned short vci; /* VCI */
76};
77
JP Abgrall511eca32014-02-12 13:46:45 -080078/*
79 * Private data for capturing on DAG devices.
80 */
81struct pcap_dag {
82 struct pcap_stat stat;
83#ifdef HAVE_DAG_STREAMS_API
84 u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */
85 u_char *dag_mem_top; /* DAG card current memory top pointer */
86#else /* HAVE_DAG_STREAMS_API */
87 void *dag_mem_base; /* DAG card memory base address */
88 u_int dag_mem_bottom; /* DAG card current memory bottom offset */
89 u_int dag_mem_top; /* DAG card current memory top offset */
90#endif /* HAVE_DAG_STREAMS_API */
91 int dag_fcs_bits; /* Number of checksum bits from link layer */
92 int dag_offset_flags; /* Flags to pass to dag_offset(). */
93 int dag_stream; /* DAG stream number */
94 int dag_timeout; /* timeout specified to pcap_open_live.
95 * Same as in linux above, introduce
96 * generally? */
97};
98
The Android Open Source Project478ab6c2009-03-03 19:30:05 -080099typedef struct pcap_dag_node {
100 struct pcap_dag_node *next;
101 pcap_t *p;
102 pid_t pid;
103} pcap_dag_node_t;
104
105static pcap_dag_node_t *pcap_dags = NULL;
106static int atexit_handler_installed = 0;
107static const unsigned short endian_test_word = 0x0100;
108
109#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word))
110
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800111#define MAX_DAG_PACKET 65536
112
113static unsigned char TempPkt[MAX_DAG_PACKET];
114
115static int dag_setfilter(pcap_t *p, struct bpf_program *fp);
116static int dag_stats(pcap_t *p, struct pcap_stat *ps);
117static int dag_set_datalink(pcap_t *p, int dlt);
118static int dag_get_datalink(pcap_t *p);
119static int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf);
120
121static void
122delete_pcap_dag(pcap_t *p)
123{
124 pcap_dag_node_t *curr = NULL, *prev = NULL;
125
126 for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) {
127 /* empty */
128 }
129
130 if (curr != NULL && curr->p == p) {
131 if (prev != NULL) {
132 prev->next = curr->next;
133 } else {
134 pcap_dags = curr->next;
135 }
136 }
137}
138
139/*
140 * Performs a graceful shutdown of the DAG card, frees dynamic memory held
141 * in the pcap_t structure, and closes the file descriptor for the DAG card.
142 */
143
144static void
JP Abgrall511eca32014-02-12 13:46:45 -0800145dag_platform_cleanup(pcap_t *p)
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800146{
JP Abgrall511eca32014-02-12 13:46:45 -0800147 struct pcap_dag *pd;
148
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800149 if (p != NULL) {
JP Abgrall511eca32014-02-12 13:46:45 -0800150 pd = p->priv;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800151#ifdef HAVE_DAG_STREAMS_API
JP Abgrall511eca32014-02-12 13:46:45 -0800152 if(dag_stop_stream(p->fd, pd->dag_stream) < 0)
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800153 fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno));
Elliott Hughesd8845d72015-10-19 18:07:04 -0700154
JP Abgrall511eca32014-02-12 13:46:45 -0800155 if(dag_detach_stream(p->fd, pd->dag_stream) < 0)
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800156 fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno));
157#else
158 if(dag_stop(p->fd) < 0)
159 fprintf(stderr,"dag_stop: %s\n", strerror(errno));
160#endif /* HAVE_DAG_STREAMS_API */
JP Abgrall511eca32014-02-12 13:46:45 -0800161 if(p->fd != -1) {
162 if(dag_close(p->fd) < 0)
163 fprintf(stderr,"dag_close: %s\n", strerror(errno));
164 p->fd = -1;
165 }
166 delete_pcap_dag(p);
167 pcap_cleanup_live_common(p);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800168 }
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800169 /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */
170}
171
172static void
173atexit_handler(void)
174{
175 while (pcap_dags != NULL) {
176 if (pcap_dags->pid == getpid()) {
JP Abgrall511eca32014-02-12 13:46:45 -0800177 dag_platform_cleanup(pcap_dags->p);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800178 } else {
179 delete_pcap_dag(pcap_dags->p);
180 }
181 }
182}
183
184static int
185new_pcap_dag(pcap_t *p)
186{
187 pcap_dag_node_t *node = NULL;
188
189 if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) {
190 return -1;
191 }
192
193 if (!atexit_handler_installed) {
194 atexit(atexit_handler);
195 atexit_handler_installed = 1;
196 }
197
198 node->next = pcap_dags;
199 node->p = p;
200 node->pid = getpid();
201
202 pcap_dags = node;
203
204 return 0;
205}
206
JP Abgrall511eca32014-02-12 13:46:45 -0800207static unsigned int
208dag_erf_ext_header_count(uint8_t * erf, size_t len)
209{
210 uint32_t hdr_num = 0;
211 uint8_t hdr_type;
212
213 /* basic sanity checks */
214 if ( erf == NULL )
215 return 0;
216 if ( len < 16 )
217 return 0;
218
219 /* check if we have any extension headers */
220 if ( (erf[8] & 0x80) == 0x00 )
221 return 0;
222
223 /* loop over the extension headers */
224 do {
Elliott Hughesd8845d72015-10-19 18:07:04 -0700225
JP Abgrall511eca32014-02-12 13:46:45 -0800226 /* sanity check we have enough bytes */
227 if ( len < (24 + (hdr_num * 8)) )
228 return hdr_num;
229
230 /* get the header type */
231 hdr_type = erf[(16 + (hdr_num * 8))];
232 hdr_num++;
233
234 } while ( hdr_type & 0x80 );
235
236 return hdr_num;
237}
238
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800239/*
240 * Read at most max_packets from the capture stream and call the callback
241 * for each of them. Returns the number of packets handled, -1 if an
242 * error occured, or -2 if we were told to break out of the loop.
243 */
244static int
245dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
246{
JP Abgrall511eca32014-02-12 13:46:45 -0800247 struct pcap_dag *pd = p->priv;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800248 unsigned int processed = 0;
JP Abgrall511eca32014-02-12 13:46:45 -0800249 int flags = pd->dag_offset_flags;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800250 unsigned int nonblocking = flags & DAGF_NONBLOCK;
JP Abgrall511eca32014-02-12 13:46:45 -0800251 unsigned int num_ext_hdr = 0;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700252 unsigned int ticks_per_second;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800253
254 /* Get the next bufferful of packets (if necessary). */
JP Abgrall511eca32014-02-12 13:46:45 -0800255 while (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size) {
Elliott Hughesd8845d72015-10-19 18:07:04 -0700256
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800257 /*
258 * Has "pcap_breakloop()" been called?
259 */
260 if (p->break_loop) {
261 /*
262 * Yes - clear the flag that indicates that
263 * it has, and return -2 to indicate that
264 * we were told to break out of the loop.
265 */
266 p->break_loop = 0;
267 return -2;
268 }
269
270#ifdef HAVE_DAG_STREAMS_API
271 /* dag_advance_stream() will block (unless nonblock is called)
272 * until 64kB of data has accumulated.
273 * If to_ms is set, it will timeout before 64kB has accumulated.
274 * We wait for 64kB because processing a few packets at a time
275 * can cause problems at high packet rates (>200kpps) due
276 * to inefficiencies.
277 * This does mean if to_ms is not specified the capture may 'hang'
278 * for long periods if the data rate is extremely slow (<64kB/sec)
279 * If non-block is specified it will return immediately. The user
280 * is then responsible for efficiency.
281 */
JP Abgrall511eca32014-02-12 13:46:45 -0800282 if ( NULL == (pd->dag_mem_top = dag_advance_stream(p->fd, pd->dag_stream, &(pd->dag_mem_bottom))) ) {
283 return -1;
284 }
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800285#else
286 /* dag_offset does not support timeouts */
JP Abgrall511eca32014-02-12 13:46:45 -0800287 pd->dag_mem_top = dag_offset(p->fd, &(pd->dag_mem_bottom), flags);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800288#endif /* HAVE_DAG_STREAMS_API */
289
JP Abgrall511eca32014-02-12 13:46:45 -0800290 if (nonblocking && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size))
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800291 {
292 /* Pcap is configured to process only available packets, and there aren't any, return immediately. */
293 return 0;
294 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700295
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800296 if(!nonblocking &&
JP Abgrall511eca32014-02-12 13:46:45 -0800297 pd->dag_timeout &&
298 (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size))
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800299 {
300 /* Blocking mode, but timeout set and no data has arrived, return anyway.*/
301 return 0;
302 }
303
304 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700305
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800306 /* Process the packets. */
JP Abgrall511eca32014-02-12 13:46:45 -0800307 while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) {
Elliott Hughesd8845d72015-10-19 18:07:04 -0700308
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800309 unsigned short packet_len = 0;
310 int caplen = 0;
311 struct pcap_pkthdr pcap_header;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700312
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800313#ifdef HAVE_DAG_STREAMS_API
JP Abgrall511eca32014-02-12 13:46:45 -0800314 dag_record_t *header = (dag_record_t *)(pd->dag_mem_bottom);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800315#else
JP Abgrall511eca32014-02-12 13:46:45 -0800316 dag_record_t *header = (dag_record_t *)(pd->dag_mem_base + pd->dag_mem_bottom);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800317#endif /* HAVE_DAG_STREAMS_API */
318
JP Abgrall511eca32014-02-12 13:46:45 -0800319 u_char *dp = ((u_char *)header); /* + dag_record_size; */
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800320 unsigned short rlen;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700321
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800322 /*
323 * Has "pcap_breakloop()" been called?
324 */
325 if (p->break_loop) {
326 /*
327 * Yes - clear the flag that indicates that
328 * it has, and return -2 to indicate that
329 * we were told to break out of the loop.
330 */
331 p->break_loop = 0;
332 return -2;
333 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700334
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800335 rlen = ntohs(header->rlen);
336 if (rlen < dag_record_size)
337 {
338 strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE);
339 return -1;
340 }
JP Abgrall511eca32014-02-12 13:46:45 -0800341 pd->dag_mem_bottom += rlen;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800342
343 /* Count lost packets. */
JP Abgrall511eca32014-02-12 13:46:45 -0800344 switch((header->type & 0x7f)) {
345 /* in these types the color value overwrites the lctr */
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800346 case TYPE_COLOR_HDLC_POS:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800347 case TYPE_COLOR_ETH:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800348 case TYPE_DSM_COLOR_HDLC_POS:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800349 case TYPE_DSM_COLOR_ETH:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800350 case TYPE_COLOR_MC_HDLC_POS:
JP Abgrall511eca32014-02-12 13:46:45 -0800351 case TYPE_COLOR_HASH_ETH:
352 case TYPE_COLOR_HASH_POS:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800353 break;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800354
355 default:
356 if (header->lctr) {
JP Abgrall511eca32014-02-12 13:46:45 -0800357 if (pd->stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) {
358 pd->stat.ps_drop = UINT_MAX;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800359 } else {
JP Abgrall511eca32014-02-12 13:46:45 -0800360 pd->stat.ps_drop += ntohs(header->lctr);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800361 }
362 }
363 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700364
JP Abgrall511eca32014-02-12 13:46:45 -0800365 if ((header->type & 0x7f) == TYPE_PAD) {
366 continue;
367 }
368
369 num_ext_hdr = dag_erf_ext_header_count(dp, rlen);
370
371 /* ERF encapsulation */
Elliott Hughesd8845d72015-10-19 18:07:04 -0700372 /* The Extensible Record Format is not dropped for this kind of encapsulation,
JP Abgrall511eca32014-02-12 13:46:45 -0800373 * and will be handled as a pseudo header by the decoding application.
374 * The information carried in the ERF header and in the optional subheader (if present)
375 * could be merged with the libpcap information, to offer a better decoding.
376 * The packet length is
377 * o the length of the packet on the link (header->wlen),
Elliott Hughesd8845d72015-10-19 18:07:04 -0700378 * o plus the length of the ERF header (dag_record_size), as the length of the
JP Abgrall511eca32014-02-12 13:46:45 -0800379 * pseudo header will be adjusted during the decoding,
380 * o plus the length of the optional subheader (if present).
381 *
382 * The capture length is header.rlen and the byte stuffing for alignment will be dropped
383 * if the capture length is greater than the packet length.
384 */
385 if (p->linktype == DLT_ERF) {
386 packet_len = ntohs(header->wlen) + dag_record_size;
387 caplen = rlen;
388 switch ((header->type & 0x7f)) {
389 case TYPE_MC_AAL5:
390 case TYPE_MC_ATM:
391 case TYPE_MC_HDLC:
392 case TYPE_MC_RAW_CHANNEL:
393 case TYPE_MC_RAW:
394 case TYPE_MC_AAL2:
395 case TYPE_COLOR_MC_HDLC_POS:
396 packet_len += 4; /* MC header */
397 break;
398
399 case TYPE_COLOR_HASH_ETH:
400 case TYPE_DSM_COLOR_ETH:
401 case TYPE_COLOR_ETH:
402 case TYPE_ETH:
403 packet_len += 2; /* ETH header */
404 break;
405 } /* switch type */
406
407 /* Include ERF extension headers */
408 packet_len += (8 * num_ext_hdr);
409
410 if (caplen > packet_len) {
411 caplen = packet_len;
412 }
413 } else {
414 /* Other kind of encapsulation according to the header Type */
415
416 /* Skip over generic ERF header */
417 dp += dag_record_size;
418 /* Skip over extension headers */
419 dp += 8 * num_ext_hdr;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700420
JP Abgrall511eca32014-02-12 13:46:45 -0800421 switch((header->type & 0x7f)) {
422 case TYPE_ATM:
423 case TYPE_AAL5:
424 if (header->type == TYPE_AAL5) {
425 packet_len = ntohs(header->wlen);
426 caplen = rlen - dag_record_size;
427 }
428 case TYPE_MC_ATM:
429 if (header->type == TYPE_MC_ATM) {
430 caplen = packet_len = ATM_CELL_SIZE;
431 dp+=4;
432 }
433 case TYPE_MC_AAL5:
434 if (header->type == TYPE_MC_AAL5) {
435 packet_len = ntohs(header->wlen);
436 caplen = rlen - dag_record_size - 4;
437 dp+=4;
438 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700439 /* Skip over extension headers */
440 caplen -= (8 * num_ext_hdr);
441
JP Abgrall511eca32014-02-12 13:46:45 -0800442 if (header->type == TYPE_ATM) {
443 caplen = packet_len = ATM_CELL_SIZE;
444 }
445 if (p->linktype == DLT_SUNATM) {
446 struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp;
447 unsigned long rawatm;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700448
JP Abgrall511eca32014-02-12 13:46:45 -0800449 rawatm = ntohl(*((unsigned long *)dp));
450 sunatm->vci = htons((rawatm >> 4) & 0xffff);
451 sunatm->vpi = (rawatm >> 20) & 0x00ff;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700452 sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) |
JP Abgrall511eca32014-02-12 13:46:45 -0800453 ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 :
Elliott Hughesd8845d72015-10-19 18:07:04 -0700454 ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 :
JP Abgrall511eca32014-02-12 13:46:45 -0800455 ((dp[ATM_HDR_SIZE] == 0xaa &&
456 dp[ATM_HDR_SIZE+1] == 0xaa &&
457 dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1)));
458
459 } else {
460 packet_len -= ATM_HDR_SIZE;
461 caplen -= ATM_HDR_SIZE;
462 dp += ATM_HDR_SIZE;
463 }
464 break;
465
466 case TYPE_COLOR_HASH_ETH:
467 case TYPE_DSM_COLOR_ETH:
468 case TYPE_COLOR_ETH:
469 case TYPE_ETH:
470 packet_len = ntohs(header->wlen);
471 packet_len -= (pd->dag_fcs_bits >> 3);
472 caplen = rlen - dag_record_size - 2;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700473 /* Skip over extension headers */
474 caplen -= (8 * num_ext_hdr);
JP Abgrall511eca32014-02-12 13:46:45 -0800475 if (caplen > packet_len) {
476 caplen = packet_len;
477 }
478 dp += 2;
479 break;
480
481 case TYPE_COLOR_HASH_POS:
482 case TYPE_DSM_COLOR_HDLC_POS:
483 case TYPE_COLOR_HDLC_POS:
484 case TYPE_HDLC_POS:
485 packet_len = ntohs(header->wlen);
486 packet_len -= (pd->dag_fcs_bits >> 3);
487 caplen = rlen - dag_record_size;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700488 /* Skip over extension headers */
489 caplen -= (8 * num_ext_hdr);
JP Abgrall511eca32014-02-12 13:46:45 -0800490 if (caplen > packet_len) {
491 caplen = packet_len;
492 }
493 break;
494
495 case TYPE_COLOR_MC_HDLC_POS:
496 case TYPE_MC_HDLC:
497 packet_len = ntohs(header->wlen);
498 packet_len -= (pd->dag_fcs_bits >> 3);
499 caplen = rlen - dag_record_size - 4;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700500 /* Skip over extension headers */
501 caplen -= (8 * num_ext_hdr);
JP Abgrall511eca32014-02-12 13:46:45 -0800502 if (caplen > packet_len) {
503 caplen = packet_len;
504 }
505 /* jump the MC_HDLC_HEADER */
506 dp += 4;
507#ifdef DLT_MTP2_WITH_PHDR
508 if (p->linktype == DLT_MTP2_WITH_PHDR) {
509 /* Add the MTP2 Pseudo Header */
510 caplen += MTP2_HDR_LEN;
511 packet_len += MTP2_HDR_LEN;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700512
JP Abgrall511eca32014-02-12 13:46:45 -0800513 TempPkt[MTP2_SENT_OFFSET] = 0;
514 TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN;
515 *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01);
516 *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff);
517 memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen);
518 dp = TempPkt;
519 }
520#endif
521 break;
522
523 case TYPE_IPV4:
524 case TYPE_IPV6:
525 packet_len = ntohs(header->wlen);
526 caplen = rlen - dag_record_size;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700527 /* Skip over extension headers */
528 caplen -= (8 * num_ext_hdr);
JP Abgrall511eca32014-02-12 13:46:45 -0800529 if (caplen > packet_len) {
530 caplen = packet_len;
531 }
532 break;
533
534 /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */
535 case TYPE_MC_RAW:
536 case TYPE_MC_RAW_CHANNEL:
537 case TYPE_IP_COUNTER:
538 case TYPE_TCP_FLOW_COUNTER:
539 case TYPE_INFINIBAND:
540 case TYPE_RAW_LINK:
541 case TYPE_INFINIBAND_LINK:
542 default:
543 /* Unhandled ERF type.
544 * Ignore rather than generating error
545 */
546 continue;
547 } /* switch type */
548
JP Abgrall511eca32014-02-12 13:46:45 -0800549 } /* ERF encapsulation */
Elliott Hughesd8845d72015-10-19 18:07:04 -0700550
JP Abgrall511eca32014-02-12 13:46:45 -0800551 if (caplen > p->snapshot)
552 caplen = p->snapshot;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800553
554 /* Run the packet filter if there is one. */
555 if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
Elliott Hughesd8845d72015-10-19 18:07:04 -0700556
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800557 /* convert between timestamp formats */
558 register unsigned long long ts;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700559
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800560 if (IS_BIGENDIAN()) {
561 ts = SWAPLL(header->ts);
562 } else {
563 ts = header->ts;
564 }
565
Elliott Hughesd8845d72015-10-19 18:07:04 -0700566 switch (p->opt.tstamp_precision) {
567 case PCAP_TSTAMP_PRECISION_NANO:
568 ticks_per_second = 1000000000;
569 break;
570 case PCAP_TSTAMP_PRECISION_MICRO:
571 default:
572 ticks_per_second = 1000000;
573 break;
574
575 }
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800576 pcap_header.ts.tv_sec = ts >> 32;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700577 ts = (ts & 0xffffffffULL) * ticks_per_second;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800578 ts += 0x80000000; /* rounding */
Elliott Hughesd8845d72015-10-19 18:07:04 -0700579 pcap_header.ts.tv_usec = ts >> 32;
580 if (pcap_header.ts.tv_usec >= ticks_per_second) {
581 pcap_header.ts.tv_usec -= ticks_per_second;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800582 pcap_header.ts.tv_sec++;
583 }
584
585 /* Fill in our own header data */
586 pcap_header.caplen = caplen;
587 pcap_header.len = packet_len;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700588
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800589 /* Count the packet. */
JP Abgrall511eca32014-02-12 13:46:45 -0800590 pd->stat.ps_recv++;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700591
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800592 /* Call the user supplied callback function */
593 callback(user, &pcap_header, dp);
Elliott Hughesd8845d72015-10-19 18:07:04 -0700594
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800595 /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */
596 processed++;
JP Abgrall511eca32014-02-12 13:46:45 -0800597 if (processed == cnt && !PACKET_COUNT_IS_UNLIMITED(cnt))
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800598 {
599 /* Reached the user-specified limit. */
600 return cnt;
601 }
602 }
603 }
604
605 return processed;
606}
607
608static int
609dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
610{
611 strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards",
612 PCAP_ERRBUF_SIZE);
613 return (-1);
614}
615
616/*
617 * Get a handle for a live capture from the given DAG device. Passing a NULL
618 * device will result in a failure. The promisc flag is ignored because DAG
JP Abgrall511eca32014-02-12 13:46:45 -0800619 * cards are always promiscuous. The to_ms parameter is used in setting the
620 * API polling parameters.
Elliott Hughesd8845d72015-10-19 18:07:04 -0700621 *
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800622 * snaplen is now also ignored, until we get per-stream slen support. Set
JP Abgrall511eca32014-02-12 13:46:45 -0800623 * slen with approprite DAG tool BEFORE pcap_activate().
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800624 *
625 * See also pcap(3).
626 */
JP Abgrall511eca32014-02-12 13:46:45 -0800627static int dag_activate(pcap_t* handle)
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800628{
JP Abgrall511eca32014-02-12 13:46:45 -0800629 struct pcap_dag *handlep = handle->priv;
630#if 0
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800631 char conf[30]; /* dag configure string */
JP Abgrall511eca32014-02-12 13:46:45 -0800632#endif
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800633 char *s;
634 int n;
635 daginf_t* daginf;
636 char * newDev = NULL;
JP Abgrall511eca32014-02-12 13:46:45 -0800637 char * device = handle->opt.source;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800638#ifdef HAVE_DAG_STREAMS_API
639 uint32_t mindata;
640 struct timeval maxwait;
641 struct timeval poll;
642#endif
643
644 if (device == NULL) {
JP Abgrall511eca32014-02-12 13:46:45 -0800645 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno));
646 return -1;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800647 }
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800648
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800649 /* Initialize some components of the pcap structure. */
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800650
651#ifdef HAVE_DAG_STREAMS_API
652 newDev = (char *)malloc(strlen(device) + 16);
653 if (newDev == NULL) {
JP Abgrall511eca32014-02-12 13:46:45 -0800654 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800655 goto fail;
656 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700657
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800658 /* Parse input name to get dag device and stream number if provided */
JP Abgrall511eca32014-02-12 13:46:45 -0800659 if (dag_parse_name(device, newDev, strlen(device) + 16, &handlep->dag_stream) < 0) {
660 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: %s\n", pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800661 goto fail;
662 }
663 device = newDev;
664
JP Abgrall511eca32014-02-12 13:46:45 -0800665 if (handlep->dag_stream%2) {
666 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture\n");
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800667 goto fail;
668 }
669#else
670 if (strncmp(device, "/dev/", 5) != 0) {
671 newDev = (char *)malloc(strlen(device) + 5);
672 if (newDev == NULL) {
JP Abgrall511eca32014-02-12 13:46:45 -0800673 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800674 goto fail;
675 }
676 strcpy(newDev, "/dev/");
677 strcat(newDev, device);
678 device = newDev;
679 }
680#endif /* HAVE_DAG_STREAMS_API */
681
682 /* setup device parameters */
683 if((handle->fd = dag_open((char *)device)) < 0) {
JP Abgrall511eca32014-02-12 13:46:45 -0800684 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800685 goto fail;
686 }
687
688#ifdef HAVE_DAG_STREAMS_API
689 /* Open requested stream. Can fail if already locked or on error */
JP Abgrall511eca32014-02-12 13:46:45 -0800690 if (dag_attach_stream(handle->fd, handlep->dag_stream, 0, 0) < 0) {
691 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s\n", pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800692 goto failclose;
693 }
694
695 /* Set up default poll parameters for stream
696 * Can be overridden by pcap_set_nonblock()
697 */
JP Abgrall511eca32014-02-12 13:46:45 -0800698 if (dag_get_stream_poll(handle->fd, handlep->dag_stream,
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800699 &mindata, &maxwait, &poll) < 0) {
JP Abgrall511eca32014-02-12 13:46:45 -0800700 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800701 goto faildetach;
702 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700703
JP Abgrall511eca32014-02-12 13:46:45 -0800704 if (handle->opt.immediate) {
705 /* Call callback immediately.
706 * XXX - is this the right way to handle this?
707 */
708 mindata = 0;
709 } else {
710 /* Amount of data to collect in Bytes before calling callbacks.
711 * Important for efficiency, but can introduce latency
712 * at low packet rates if to_ms not set!
713 */
714 mindata = 65536;
715 }
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800716
JP Abgrall511eca32014-02-12 13:46:45 -0800717 /* Obey opt.timeout (was to_ms) if supplied. This is a good idea!
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800718 * Recommend 10-100ms. Calls will time out even if no data arrived.
719 */
JP Abgrall511eca32014-02-12 13:46:45 -0800720 maxwait.tv_sec = handle->opt.timeout/1000;
721 maxwait.tv_usec = (handle->opt.timeout%1000) * 1000;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800722
JP Abgrall511eca32014-02-12 13:46:45 -0800723 if (dag_set_stream_poll(handle->fd, handlep->dag_stream,
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800724 mindata, &maxwait, &poll) < 0) {
JP Abgrall511eca32014-02-12 13:46:45 -0800725 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800726 goto faildetach;
727 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700728
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800729#else
JP Abgrall511eca32014-02-12 13:46:45 -0800730 if((handlep->dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) {
731 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800732 goto failclose;
733 }
734
735#endif /* HAVE_DAG_STREAMS_API */
736
737 /* XXX Not calling dag_configure() to set slen; this is unsafe in
738 * multi-stream environments as the gpp config is global.
739 * Once the firmware provides 'per-stream slen' this can be supported
740 * again via the Config API without side-effects */
741#if 0
742 /* set the card snap length to the specified snaplen parameter */
743 /* This is a really bad idea, as different cards have different
744 * valid slen ranges. Should fix in Config API. */
JP Abgrall511eca32014-02-12 13:46:45 -0800745 if (handle->snapshot == 0 || handle->snapshot > MAX_DAG_SNAPLEN) {
746 handle->snapshot = MAX_DAG_SNAPLEN;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800747 } else if (snaplen < MIN_DAG_SNAPLEN) {
JP Abgrall511eca32014-02-12 13:46:45 -0800748 handle->snapshot = MIN_DAG_SNAPLEN;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800749 }
750 /* snap len has to be a multiple of 4 */
Elliott Hughesd8845d72015-10-19 18:07:04 -0700751 snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800752
753 if(dag_configure(handle->fd, conf) < 0) {
JP Abgrall511eca32014-02-12 13:46:45 -0800754 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800755 goto faildetach;
756 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700757#endif
758
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800759#ifdef HAVE_DAG_STREAMS_API
JP Abgrall511eca32014-02-12 13:46:45 -0800760 if(dag_start_stream(handle->fd, handlep->dag_stream) < 0) {
761 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s\n", device, pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800762 goto faildetach;
763 }
764#else
765 if(dag_start(handle->fd) < 0) {
JP Abgrall511eca32014-02-12 13:46:45 -0800766 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800767 goto failclose;
768 }
769#endif /* HAVE_DAG_STREAMS_API */
770
771 /*
772 * Important! You have to ensure bottom is properly
773 * initialized to zero on startup, it won't give you
774 * a compiler warning if you make this mistake!
775 */
JP Abgrall511eca32014-02-12 13:46:45 -0800776 handlep->dag_mem_bottom = 0;
777 handlep->dag_mem_top = 0;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800778
JP Abgrall511eca32014-02-12 13:46:45 -0800779 /*
780 * Find out how many FCS bits we should strip.
781 * First, query the card to see if it strips the FCS.
782 */
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800783 daginf = dag_info(handle->fd);
JP Abgrall511eca32014-02-12 13:46:45 -0800784 if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code)) {
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800785 /* DAG 4.2S and 4.23S already strip the FCS. Stripping the final word again truncates the packet. */
JP Abgrall511eca32014-02-12 13:46:45 -0800786 handlep->dag_fcs_bits = 0;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800787
JP Abgrall511eca32014-02-12 13:46:45 -0800788 /* Note that no FCS will be supplied. */
789 handle->linktype_ext = LT_FCS_DATALINK_EXT(0);
790 } else {
791 /*
792 * Start out assuming it's 32 bits.
793 */
794 handlep->dag_fcs_bits = 32;
795
796 /* Allow an environment variable to override. */
797 if ((s = getenv("ERF_FCS_BITS")) != NULL) {
798 if ((n = atoi(s)) == 0 || n == 16 || n == 32) {
799 handlep->dag_fcs_bits = n;
800 } else {
801 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
802 "pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n);
803 goto failstop;
804 }
805 }
806
807 /*
808 * Did the user request that they not be stripped?
809 */
810 if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) {
811 /* Yes. Note the number of bytes that will be
812 supplied. */
813 handle->linktype_ext = LT_FCS_DATALINK_EXT(handlep->dag_fcs_bits/16);
814
815 /* And don't strip them. */
816 handlep->dag_fcs_bits = 0;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800817 }
818 }
819
JP Abgrall511eca32014-02-12 13:46:45 -0800820 handlep->dag_timeout = handle->opt.timeout;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800821
822 handle->linktype = -1;
JP Abgrall511eca32014-02-12 13:46:45 -0800823 if (dag_get_datalink(handle) < 0)
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800824 goto failstop;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700825
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800826 handle->bufsize = 0;
827
828 if (new_pcap_dag(handle) < 0) {
JP Abgrall511eca32014-02-12 13:46:45 -0800829 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800830 goto failstop;
831 }
832
833 /*
834 * "select()" and "poll()" don't work on DAG device descriptors.
835 */
836 handle->selectable_fd = -1;
837
838 if (newDev != NULL) {
839 free((char *)newDev);
840 }
841
842 handle->read_op = dag_read;
843 handle->inject_op = dag_inject;
844 handle->setfilter_op = dag_setfilter;
845 handle->setdirection_op = NULL; /* Not implemented.*/
846 handle->set_datalink_op = dag_set_datalink;
847 handle->getnonblock_op = pcap_getnonblock_fd;
848 handle->setnonblock_op = dag_setnonblock;
849 handle->stats_op = dag_stats;
JP Abgrall511eca32014-02-12 13:46:45 -0800850 handle->cleanup_op = dag_platform_cleanup;
851 handlep->stat.ps_drop = 0;
852 handlep->stat.ps_recv = 0;
853 handlep->stat.ps_ifdrop = 0;
854 return 0;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800855
Elliott Hughesd8845d72015-10-19 18:07:04 -0700856#ifdef HAVE_DAG_STREAMS_API
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800857failstop:
JP Abgrall511eca32014-02-12 13:46:45 -0800858 if (dag_stop_stream(handle->fd, handlep->dag_stream) < 0) {
859 fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800860 }
Elliott Hughesd8845d72015-10-19 18:07:04 -0700861
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800862faildetach:
JP Abgrall511eca32014-02-12 13:46:45 -0800863 if (dag_detach_stream(handle->fd, handlep->dag_stream) < 0)
864 fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno));
865#else
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800866failstop:
JP Abgrall511eca32014-02-12 13:46:45 -0800867 if (dag_stop(handle->fd) < 0)
868 fprintf(stderr,"dag_stop: %s\n", strerror(errno));
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800869#endif /* HAVE_DAG_STREAMS_API */
Elliott Hughesd8845d72015-10-19 18:07:04 -0700870
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800871failclose:
JP Abgrall511eca32014-02-12 13:46:45 -0800872 if (dag_close(handle->fd) < 0)
873 fprintf(stderr,"dag_close: %s\n", strerror(errno));
874 delete_pcap_dag(handle);
875
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800876fail:
JP Abgrall511eca32014-02-12 13:46:45 -0800877 pcap_cleanup_live_common(handle);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800878 if (newDev != NULL) {
879 free((char *)newDev);
880 }
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800881
JP Abgrall511eca32014-02-12 13:46:45 -0800882 return PCAP_ERROR;
883}
884
885pcap_t *dag_create(const char *device, char *ebuf, int *is_ours)
886{
887 const char *cp;
888 char *cpend;
889 long devnum;
890 pcap_t *p;
891#ifdef HAVE_DAG_STREAMS_API
892 long stream = 0;
893#endif
894
895 /* Does this look like a DAG device? */
896 cp = strrchr(device, '/');
897 if (cp == NULL)
898 cp = device;
899 /* Does it begin with "dag"? */
900 if (strncmp(cp, "dag", 3) != 0) {
901 /* Nope, doesn't begin with "dag" */
902 *is_ours = 0;
903 return NULL;
904 }
905 /* Yes - is "dag" followed by a number from 0 to DAG_MAX_BOARDS-1 */
906 cp += 3;
907 devnum = strtol(cp, &cpend, 10);
908#ifdef HAVE_DAG_STREAMS_API
909 if (*cpend == ':') {
910 /* Followed by a stream number. */
911 stream = strtol(++cpend, &cpend, 10);
912 }
913#endif
914 if (cpend == cp || *cpend != '\0') {
915 /* Not followed by a number. */
916 *is_ours = 0;
917 return NULL;
918 }
919 if (devnum < 0 || devnum >= DAG_MAX_BOARDS) {
920 /* Followed by a non-valid number. */
921 *is_ours = 0;
922 return NULL;
923 }
924#ifdef HAVE_DAG_STREAMS_API
925 if (stream <0 || stream >= DAG_STREAM_MAX) {
926 /* Followed by a non-valid stream number. */
927 *is_ours = 0;
928 return NULL;
929 }
930#endif
931
932 /* OK, it's probably ours. */
933 *is_ours = 1;
934
935 p = pcap_create_common(device, ebuf, sizeof (struct pcap_dag));
936 if (p == NULL)
937 return NULL;
938
939 p->activate_op = dag_activate;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700940
941 /*
942 * We claim that we support microsecond and nanosecond time
943 * stamps.
944 *
945 * XXX Our native precision is 2^-32s, but libpcap doesn't support
946 * power of two precisions yet. We can convert to either MICRO or NANO.
947 */
948 p->tstamp_precision_count = 2;
949 p->tstamp_precision_list = malloc(2 * sizeof(u_int));
950 if (p->tstamp_precision_list == NULL) {
951 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
952 pcap_strerror(errno));
953 if (p->tstamp_type_list != NULL)
954 free(p->tstamp_type_list);
955 free(p);
956 return NULL;
957 }
958 p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
959 p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
JP Abgrall511eca32014-02-12 13:46:45 -0800960 return p;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800961}
962
963static int
964dag_stats(pcap_t *p, struct pcap_stat *ps) {
JP Abgrall511eca32014-02-12 13:46:45 -0800965 struct pcap_dag *pd = p->priv;
966
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800967 /* This needs to be filled out correctly. Hopefully a dagapi call will
968 provide all necessary information.
969 */
JP Abgrall511eca32014-02-12 13:46:45 -0800970 /*pd->stat.ps_recv = 0;*/
971 /*pd->stat.ps_drop = 0;*/
Elliott Hughesd8845d72015-10-19 18:07:04 -0700972
JP Abgrall511eca32014-02-12 13:46:45 -0800973 *ps = pd->stat;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700974
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800975 return 0;
976}
977
978/*
JP Abgrall511eca32014-02-12 13:46:45 -0800979 * Previously we just generated a list of all possible names and let
980 * pcap_add_if() attempt to open each one, but with streams this adds up
981 * to 81 possibilities which is inefficient.
982 *
983 * Since we know more about the devices we can prune the tree here.
984 * pcap_add_if() will still retest each device but the total number of
985 * open attempts will still be much less than the naive approach.
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800986 */
987int
JP Abgrall511eca32014-02-12 13:46:45 -0800988dag_findalldevs(pcap_if_t **devlistp, char *errbuf)
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800989{
990 char name[12]; /* XXX - pick a size */
991 int ret = 0;
992 int c;
JP Abgrall511eca32014-02-12 13:46:45 -0800993 char dagname[DAGNAME_BUFSIZE];
994 int dagstream;
995 int dagfd;
Elliott Hughesd8845d72015-10-19 18:07:04 -0700996 dag_card_inf_t *inf;
997 char *description;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -0800998
JP Abgrall511eca32014-02-12 13:46:45 -0800999 /* Try all the DAGs 0-DAG_MAX_BOARDS */
1000 for (c = 0; c < DAG_MAX_BOARDS; c++) {
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001001 snprintf(name, 12, "dag%d", c);
JP Abgrall511eca32014-02-12 13:46:45 -08001002 if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream))
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001003 {
JP Abgrall511eca32014-02-12 13:46:45 -08001004 return -1;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001005 }
Elliott Hughesd8845d72015-10-19 18:07:04 -07001006 description = NULL;
JP Abgrall511eca32014-02-12 13:46:45 -08001007 if ( (dagfd = dag_open(dagname)) >= 0 ) {
Elliott Hughesd8845d72015-10-19 18:07:04 -07001008 if ((inf = dag_pciinfo(dagfd)))
1009 description = dag_device_name(inf->device_code, 1);
1010 if (pcap_add_if(devlistp, name, 0, description, errbuf) == -1) {
JP Abgrall511eca32014-02-12 13:46:45 -08001011 /*
1012 * Failure.
1013 */
1014 ret = -1;
1015 }
1016#ifdef HAVE_DAG_STREAMS_API
1017 {
1018 int stream, rxstreams;
1019 rxstreams = dag_rx_get_stream_count(dagfd);
1020 for(stream=0;stream<DAG_STREAM_MAX;stream+=2) {
1021 if (0 == dag_attach_stream(dagfd, stream, 0, 0)) {
1022 dag_detach_stream(dagfd, stream);
1023
1024 snprintf(name, 10, "dag%d:%d", c, stream);
Elliott Hughesd8845d72015-10-19 18:07:04 -07001025 if (pcap_add_if(devlistp, name, 0, description, errbuf) == -1) {
JP Abgrall511eca32014-02-12 13:46:45 -08001026 /*
1027 * Failure.
1028 */
1029 ret = -1;
1030 }
Elliott Hughesd8845d72015-10-19 18:07:04 -07001031
JP Abgrall511eca32014-02-12 13:46:45 -08001032 rxstreams--;
1033 if(rxstreams <= 0) {
1034 break;
1035 }
1036 }
Elliott Hughesd8845d72015-10-19 18:07:04 -07001037 }
JP Abgrall511eca32014-02-12 13:46:45 -08001038 }
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001039#endif /* HAVE_DAG_STREAMS_API */
JP Abgrall511eca32014-02-12 13:46:45 -08001040 dag_close(dagfd);
1041 }
1042
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001043 }
1044 return (ret);
1045}
1046
1047/*
1048 * Installs the given bpf filter program in the given pcap structure. There is
1049 * no attempt to store the filter in kernel memory as that is not supported
1050 * with DAG cards.
1051 */
1052static int
1053dag_setfilter(pcap_t *p, struct bpf_program *fp)
1054{
1055 if (!p)
1056 return -1;
1057 if (!fp) {
1058 strncpy(p->errbuf, "setfilter: No filter specified",
1059 sizeof(p->errbuf));
1060 return -1;
1061 }
1062
1063 /* Make our private copy of the filter */
1064
1065 if (install_bpf_program(p, fp) < 0)
1066 return -1;
1067
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001068 return (0);
1069}
1070
1071static int
1072dag_set_datalink(pcap_t *p, int dlt)
1073{
1074 p->linktype = dlt;
1075
1076 return (0);
1077}
1078
1079static int
1080dag_setnonblock(pcap_t *p, int nonblock, char *errbuf)
1081{
JP Abgrall511eca32014-02-12 13:46:45 -08001082 struct pcap_dag *pd = p->priv;
1083
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001084 /*
1085 * Set non-blocking mode on the FD.
1086 * XXX - is that necessary? If not, don't bother calling it,
1087 * and have a "dag_getnonblock()" function that looks at
JP Abgrall511eca32014-02-12 13:46:45 -08001088 * "pd->dag_offset_flags".
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001089 */
1090 if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0)
1091 return (-1);
1092#ifdef HAVE_DAG_STREAMS_API
1093 {
1094 uint32_t mindata;
1095 struct timeval maxwait;
1096 struct timeval poll;
Elliott Hughesd8845d72015-10-19 18:07:04 -07001097
JP Abgrall511eca32014-02-12 13:46:45 -08001098 if (dag_get_stream_poll(p->fd, pd->dag_stream,
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001099 &mindata, &maxwait, &poll) < 0) {
1100 snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno));
1101 return -1;
1102 }
Elliott Hughesd8845d72015-10-19 18:07:04 -07001103
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001104 /* Amount of data to collect in Bytes before calling callbacks.
1105 * Important for efficiency, but can introduce latency
1106 * at low packet rates if to_ms not set!
1107 */
1108 if(nonblock)
1109 mindata = 0;
1110 else
1111 mindata = 65536;
Elliott Hughesd8845d72015-10-19 18:07:04 -07001112
JP Abgrall511eca32014-02-12 13:46:45 -08001113 if (dag_set_stream_poll(p->fd, pd->dag_stream,
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001114 mindata, &maxwait, &poll) < 0) {
1115 snprintf(errbuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno));
1116 return -1;
1117 }
1118 }
1119#endif /* HAVE_DAG_STREAMS_API */
1120 if (nonblock) {
JP Abgrall511eca32014-02-12 13:46:45 -08001121 pd->dag_offset_flags |= DAGF_NONBLOCK;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001122 } else {
JP Abgrall511eca32014-02-12 13:46:45 -08001123 pd->dag_offset_flags &= ~DAGF_NONBLOCK;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001124 }
1125 return (0);
1126}
Elliott Hughesd8845d72015-10-19 18:07:04 -07001127
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001128static int
1129dag_get_datalink(pcap_t *p)
1130{
JP Abgrall511eca32014-02-12 13:46:45 -08001131 struct pcap_dag *pd = p->priv;
1132 int index=0, dlt_index=0;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001133 uint8_t types[255];
1134
1135 memset(types, 0, 255);
1136
1137 if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) {
1138 (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno));
1139 return (-1);
1140 }
1141
1142 p->linktype = 0;
1143
JP Abgrall511eca32014-02-12 13:46:45 -08001144#ifdef HAVE_DAG_GET_STREAM_ERF_TYPES
1145 /* Get list of possible ERF types for this card */
1146 if (dag_get_stream_erf_types(p->fd, pd->dag_stream, types, 255) < 0) {
1147 snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_stream_erf_types: %s", pcap_strerror(errno));
Elliott Hughesd8845d72015-10-19 18:07:04 -07001148 return (-1);
JP Abgrall511eca32014-02-12 13:46:45 -08001149 }
Elliott Hughesd8845d72015-10-19 18:07:04 -07001150
JP Abgrall511eca32014-02-12 13:46:45 -08001151 while (types[index]) {
1152
1153#elif defined HAVE_DAG_GET_ERF_TYPES
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001154 /* Get list of possible ERF types for this card */
1155 if (dag_get_erf_types(p->fd, types, 255) < 0) {
1156 snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_erf_types: %s", pcap_strerror(errno));
Elliott Hughesd8845d72015-10-19 18:07:04 -07001157 return (-1);
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001158 }
Elliott Hughesd8845d72015-10-19 18:07:04 -07001159
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001160 while (types[index]) {
1161#else
1162 /* Check the type through a dagapi call. */
1163 types[index] = dag_linktype(p->fd);
1164
1165 {
1166#endif
JP Abgrall511eca32014-02-12 13:46:45 -08001167 switch((types[index] & 0x7f)) {
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001168
1169 case TYPE_HDLC_POS:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001170 case TYPE_COLOR_HDLC_POS:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001171 case TYPE_DSM_COLOR_HDLC_POS:
JP Abgrall511eca32014-02-12 13:46:45 -08001172 case TYPE_COLOR_HASH_POS:
1173
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001174 if (p->dlt_list != NULL) {
JP Abgrall511eca32014-02-12 13:46:45 -08001175 p->dlt_list[dlt_index++] = DLT_CHDLC;
1176 p->dlt_list[dlt_index++] = DLT_PPP_SERIAL;
1177 p->dlt_list[dlt_index++] = DLT_FRELAY;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001178 }
1179 if(!p->linktype)
1180 p->linktype = DLT_CHDLC;
1181 break;
1182
1183 case TYPE_ETH:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001184 case TYPE_COLOR_ETH:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001185 case TYPE_DSM_COLOR_ETH:
JP Abgrall511eca32014-02-12 13:46:45 -08001186 case TYPE_COLOR_HASH_ETH:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001187 /*
1188 * This is (presumably) a real Ethernet capture; give it a
1189 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
1190 * that an application can let you choose it, in case you're
1191 * capturing DOCSIS traffic that a Cisco Cable Modem
1192 * Termination System is putting out onto an Ethernet (it
1193 * doesn't put an Ethernet header onto the wire, it puts raw
1194 * DOCSIS frames out on the wire inside the low-level
1195 * Ethernet framing).
1196 */
1197 if (p->dlt_list != NULL) {
JP Abgrall511eca32014-02-12 13:46:45 -08001198 p->dlt_list[dlt_index++] = DLT_EN10MB;
1199 p->dlt_list[dlt_index++] = DLT_DOCSIS;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001200 }
1201 if(!p->linktype)
1202 p->linktype = DLT_EN10MB;
1203 break;
1204
Elliott Hughesd8845d72015-10-19 18:07:04 -07001205 case TYPE_ATM:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001206 case TYPE_AAL5:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001207 case TYPE_MC_ATM:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001208 case TYPE_MC_AAL5:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001209 if (p->dlt_list != NULL) {
JP Abgrall511eca32014-02-12 13:46:45 -08001210 p->dlt_list[dlt_index++] = DLT_ATM_RFC1483;
1211 p->dlt_list[dlt_index++] = DLT_SUNATM;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001212 }
1213 if(!p->linktype)
1214 p->linktype = DLT_ATM_RFC1483;
1215 break;
1216
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001217 case TYPE_COLOR_MC_HDLC_POS:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001218 case TYPE_MC_HDLC:
1219 if (p->dlt_list != NULL) {
JP Abgrall511eca32014-02-12 13:46:45 -08001220 p->dlt_list[dlt_index++] = DLT_CHDLC;
1221 p->dlt_list[dlt_index++] = DLT_PPP_SERIAL;
1222 p->dlt_list[dlt_index++] = DLT_FRELAY;
1223 p->dlt_list[dlt_index++] = DLT_MTP2;
1224 p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR;
1225 p->dlt_list[dlt_index++] = DLT_LAPD;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001226 }
1227 if(!p->linktype)
1228 p->linktype = DLT_CHDLC;
1229 break;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001230
JP Abgrall511eca32014-02-12 13:46:45 -08001231 case TYPE_IPV4:
1232 case TYPE_IPV6:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001233 if(!p->linktype)
JP Abgrall511eca32014-02-12 13:46:45 -08001234 p->linktype = DLT_RAW;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001235 break;
1236
JP Abgrall511eca32014-02-12 13:46:45 -08001237 case TYPE_LEGACY:
1238 case TYPE_MC_RAW:
1239 case TYPE_MC_RAW_CHANNEL:
1240 case TYPE_IP_COUNTER:
1241 case TYPE_TCP_FLOW_COUNTER:
1242 case TYPE_INFINIBAND:
1243 case TYPE_RAW_LINK:
1244 case TYPE_INFINIBAND_LINK:
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001245 default:
JP Abgrall511eca32014-02-12 13:46:45 -08001246 /* Libpcap cannot deal with these types yet */
1247 /* Add no 'native' DLTs, but still covered by DLT_ERF */
1248 break;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001249
1250 } /* switch */
JP Abgrall511eca32014-02-12 13:46:45 -08001251 index++;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001252 }
1253
JP Abgrall511eca32014-02-12 13:46:45 -08001254 p->dlt_list[dlt_index++] = DLT_ERF;
1255
1256 p->dlt_count = dlt_index;
1257
1258 if(!p->linktype)
1259 p->linktype = DLT_ERF;
The Android Open Source Project478ab6c2009-03-03 19:30:05 -08001260
1261 return p->linktype;
1262}