/* Determines how much data is available for reading on the DAG card and * updates the various offsets accordingly */ static int dag_available(libtrace_t *libtrace) { if (FORMAT_DATA->diff > 0) return FORMAT_DATA->diff; FORMAT_DATA->bottom = FORMAT_DATA->top; FORMAT_DATA->top = dag_offset( FORMAT_DATA->fd, &(FORMAT_DATA->bottom), DAGF_NONBLOCK); FORMAT_DATA->diff = FORMAT_DATA->top - FORMAT_DATA->bottom; FORMAT_DATA->offset = 0; return FORMAT_DATA->diff; }
static int legacy_read_packet(struct dag_context* cap, unsigned char* dst, struct cap_header* head){ const ssize_t diff = cap->top - cap->bottom; /* no packet in buffer */ if ( diff < dag_record_size ){ cap->top = dag_offset(cap->fd, &cap->bottom, 0); return 0; /* process eventual packages in the next batch */ } dag_record_t* dr = (dag_record_t *)(cap->buffer + cap->bottom); const size_t rlen = ntohs(dr->rlen); /* not enough data in buffer */ if ( diff < rlen ){ cap->top = dag_offset(cap->fd, &cap->bottom, 0); return 0; /* process eventual packages in the next batch */ } /* process packet */ int ret = process_packet(cap, dr, dst, head); cap->bottom += rlen; /* advance read position */ return ret; }
/* * Read at most max_packets from the capture stream and call the callback * for each of them. Returns the number of packets handled, -1 if an * error occured, or -2 if we were told to break out of the loop. */ static int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { unsigned int processed = 0; int flags = p->md.dag_offset_flags; unsigned int nonblocking = flags & DAGF_NONBLOCK; /* Get the next bufferful of packets (if necessary). */ while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) { /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that * it has, and return -2 to indicate that * we were told to break out of the loop. */ p->break_loop = 0; return -2; } #ifdef HAVE_DAG_STREAMS_API /* dag_advance_stream() will block (unless nonblock is called) * until 64kB of data has accumulated. * If to_ms is set, it will timeout before 64kB has accumulated. * We wait for 64kB because processing a few packets at a time * can cause problems at high packet rates (>200kpps) due * to inefficiencies. * This does mean if to_ms is not specified the capture may 'hang' * for long periods if the data rate is extremely slow (<64kB/sec) * If non-block is specified it will return immediately. The user * is then responsible for efficiency. */ p->md.dag_mem_top = dag_advance_stream(p->fd, p->md.dag_stream, &(p->md.dag_mem_bottom)); #else /* dag_offset does not support timeouts */ p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), flags); #endif /* HAVE_DAG_STREAMS_API */ if (nonblocking && (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size)) { /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ return 0; } if(!nonblocking && p->md.dag_timeout && (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size)) { /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ return 0; } } /* Process the packets. */ while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) { unsigned short packet_len = 0; int caplen = 0; struct pcap_pkthdr pcap_header; #ifdef HAVE_DAG_STREAMS_API dag_record_t *header = (dag_record_t *)(p->md.dag_mem_bottom); #else dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom); #endif /* HAVE_DAG_STREAMS_API */ u_char *dp = ((u_char *)header) + dag_record_size; unsigned short rlen; /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that * it has, and return -2 to indicate that * we were told to break out of the loop. */ p->break_loop = 0; return -2; } rlen = ntohs(header->rlen); if (rlen < dag_record_size) { strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); return -1; } p->md.dag_mem_bottom += rlen; switch(header->type) { case TYPE_ATM: #ifdef TYPE_AAL5 case TYPE_AAL5: if (header->type == TYPE_AAL5) { packet_len = ntohs(header->wlen); caplen = rlen - dag_record_size; } #endif #ifdef TYPE_MC_ATM case TYPE_MC_ATM: if (header->type == TYPE_MC_ATM) { caplen = packet_len = ATM_CELL_SIZE; dp+=4; } #endif #ifdef TYPE_MC_AAL5 case TYPE_MC_AAL5: if (header->type == TYPE_MC_AAL5) { packet_len = ntohs(header->wlen); caplen = rlen - dag_record_size - 4; dp+=4; } #endif if (header->type == TYPE_ATM) { caplen = packet_len = ATM_CELL_SIZE; } if (p->linktype == DLT_SUNATM) { struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; unsigned long rawatm; rawatm = ntohl(*((unsigned long *)dp)); sunatm->vci = htons((rawatm >> 4) & 0xffff); sunatm->vpi = (rawatm >> 20) & 0x00ff; sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : ((dp[ATM_HDR_SIZE] == 0xaa && dp[ATM_HDR_SIZE+1] == 0xaa && dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); } else { packet_len -= ATM_HDR_SIZE; caplen -= ATM_HDR_SIZE; dp += ATM_HDR_SIZE; } break; #ifdef TYPE_COLOR_ETH case TYPE_COLOR_ETH: #endif case TYPE_ETH: packet_len = ntohs(header->wlen); packet_len -= (p->md.dag_fcs_bits >> 3); caplen = rlen - dag_record_size - 2; if (caplen > packet_len) { caplen = packet_len; } dp += 2; break; #ifdef TYPE_COLOR_HDLC_POS case TYPE_COLOR_HDLC_POS: #endif case TYPE_HDLC_POS: packet_len = ntohs(header->wlen); packet_len -= (p->md.dag_fcs_bits >> 3); caplen = rlen - dag_record_size; if (caplen > packet_len) { caplen = packet_len; } break; #ifdef TYPE_MC_HDLC case TYPE_MC_HDLC: packet_len = ntohs(header->wlen); packet_len -= (p->md.dag_fcs_bits >> 3); caplen = rlen - dag_record_size - 4; if (caplen > packet_len) { caplen = packet_len; } dp += 4; break; #endif } if (caplen > p->snapshot) caplen = p->snapshot; /* Count lost packets. */ switch(header->type) { #ifdef TYPE_COLOR_HDLC_POS /* in this type the color value overwrites the lctr */ case TYPE_COLOR_HDLC_POS: break; #endif #ifdef TYPE_COLOR_ETH /* in this type the color value overwrites the lctr */ case TYPE_COLOR_ETH: break; #endif default: if (header->lctr) { if (p->md.stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { p->md.stat.ps_drop = UINT_MAX; } else { p->md.stat.ps_drop += ntohs(header->lctr); } } } /* Run the packet filter if there is one. */ if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) { /* convert between timestamp formats */ register unsigned long long ts; if (IS_BIGENDIAN()) { ts = SWAP_TS(header->ts); } else { ts = header->ts; } pcap_header.ts.tv_sec = ts >> 32; ts = (ts & 0xffffffffULL) * 1000000; ts += 0x80000000; /* rounding */ pcap_header.ts.tv_usec = ts >> 32; if (pcap_header.ts.tv_usec >= 1000000) { pcap_header.ts.tv_usec -= 1000000; pcap_header.ts.tv_sec++; } /* Fill in our own header data */ pcap_header.caplen = caplen; pcap_header.len = packet_len; /* Count the packet. */ p->md.stat.ps_recv++; /* Call the user supplied callback function */ callback(user, &pcap_header, dp); /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ processed++; if (processed == cnt) { /* Reached the user-specified limit. */ return cnt; } } }
/* * Read at most max_packets from the capture stream and call the callback * for each of them. Returns the number of packets handled, -1 if an * error occured, or -2 if we were told to break out of the loop. */ static int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { struct pcap_dag *pd = p->priv; unsigned int processed = 0; int flags = pd->dag_offset_flags; unsigned int nonblocking = flags & DAGF_NONBLOCK; unsigned int num_ext_hdr = 0; unsigned int ticks_per_second; /* Get the next bufferful of packets (if necessary). */ while (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size) { /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that * it has, and return -2 to indicate that * we were told to break out of the loop. */ p->break_loop = 0; return -2; } #ifdef HAVE_DAG_STREAMS_API /* dag_advance_stream() will block (unless nonblock is called) * until 64kB of data has accumulated. * If to_ms is set, it will timeout before 64kB has accumulated. * We wait for 64kB because processing a few packets at a time * can cause problems at high packet rates (>200kpps) due * to inefficiencies. * This does mean if to_ms is not specified the capture may 'hang' * for long periods if the data rate is extremely slow (<64kB/sec) * If non-block is specified it will return immediately. The user * is then responsible for efficiency. */ if ( NULL == (pd->dag_mem_top = dag_advance_stream(p->fd, pd->dag_stream, &(pd->dag_mem_bottom))) ) { return -1; } #else /* dag_offset does not support timeouts */ pd->dag_mem_top = dag_offset(p->fd, &(pd->dag_mem_bottom), flags); #endif /* HAVE_DAG_STREAMS_API */ if (nonblocking && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) { /* Pcap is configured to process only available packets, and there aren't any, return immediately. */ return 0; } if(!nonblocking && pd->dag_timeout && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size)) { /* Blocking mode, but timeout set and no data has arrived, return anyway.*/ return 0; } } /* Process the packets. */ while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) { unsigned short packet_len = 0; int caplen = 0; struct pcap_pkthdr pcap_header; #ifdef HAVE_DAG_STREAMS_API dag_record_t *header = (dag_record_t *)(pd->dag_mem_bottom); #else dag_record_t *header = (dag_record_t *)(pd->dag_mem_base + pd->dag_mem_bottom); #endif /* HAVE_DAG_STREAMS_API */ u_char *dp = ((u_char *)header); /* + dag_record_size; */ unsigned short rlen; /* * Has "pcap_breakloop()" been called? */ if (p->break_loop) { /* * Yes - clear the flag that indicates that * it has, and return -2 to indicate that * we were told to break out of the loop. */ p->break_loop = 0; return -2; } rlen = ntohs(header->rlen); if (rlen < dag_record_size) { strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE); return -1; } pd->dag_mem_bottom += rlen; /* Count lost packets. */ switch((header->type & 0x7f)) { /* in these types the color value overwrites the lctr */ case TYPE_COLOR_HDLC_POS: case TYPE_COLOR_ETH: case TYPE_DSM_COLOR_HDLC_POS: case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_MC_HDLC_POS: case TYPE_COLOR_HASH_ETH: case TYPE_COLOR_HASH_POS: break; default: if (header->lctr) { if (pd->stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { pd->stat.ps_drop = UINT_MAX; } else { pd->stat.ps_drop += ntohs(header->lctr); } } } if ((header->type & 0x7f) == TYPE_PAD) { continue; } num_ext_hdr = dag_erf_ext_header_count(dp, rlen); /* ERF encapsulation */ /* The Extensible Record Format is not dropped for this kind of encapsulation, * and will be handled as a pseudo header by the decoding application. * The information carried in the ERF header and in the optional subheader (if present) * could be merged with the libpcap information, to offer a better decoding. * The packet length is * o the length of the packet on the link (header->wlen), * o plus the length of the ERF header (dag_record_size), as the length of the * pseudo header will be adjusted during the decoding, * o plus the length of the optional subheader (if present). * * The capture length is header.rlen and the byte stuffing for alignment will be dropped * if the capture length is greater than the packet length. */ if (p->linktype == DLT_ERF) { packet_len = ntohs(header->wlen) + dag_record_size; caplen = rlen; switch ((header->type & 0x7f)) { case TYPE_MC_AAL5: case TYPE_MC_ATM: case TYPE_MC_HDLC: case TYPE_MC_RAW_CHANNEL: case TYPE_MC_RAW: case TYPE_MC_AAL2: case TYPE_COLOR_MC_HDLC_POS: packet_len += 4; /* MC header */ break; case TYPE_COLOR_HASH_ETH: case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_ETH: case TYPE_ETH: packet_len += 2; /* ETH header */ break; } /* switch type */ /* Include ERF extension headers */ packet_len += (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } } else { /* Other kind of encapsulation according to the header Type */ /* Skip over generic ERF header */ dp += dag_record_size; /* Skip over extension headers */ dp += 8 * num_ext_hdr; switch((header->type & 0x7f)) { case TYPE_ATM: case TYPE_AAL5: if (header->type == TYPE_AAL5) { packet_len = ntohs(header->wlen); caplen = rlen - dag_record_size; } case TYPE_MC_ATM: if (header->type == TYPE_MC_ATM) { caplen = packet_len = ATM_CELL_SIZE; dp+=4; } case TYPE_MC_AAL5: if (header->type == TYPE_MC_AAL5) { packet_len = ntohs(header->wlen); caplen = rlen - dag_record_size - 4; dp+=4; } /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (header->type == TYPE_ATM) { caplen = packet_len = ATM_CELL_SIZE; } if (p->linktype == DLT_SUNATM) { struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp; unsigned long rawatm; rawatm = ntohl(*((unsigned long *)dp)); sunatm->vci = htons((rawatm >> 4) & 0xffff); sunatm->vpi = (rawatm >> 20) & 0x00ff; sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) | ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 : ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 : ((dp[ATM_HDR_SIZE] == 0xaa && dp[ATM_HDR_SIZE+1] == 0xaa && dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1))); } else { packet_len -= ATM_HDR_SIZE; caplen -= ATM_HDR_SIZE; dp += ATM_HDR_SIZE; } break; case TYPE_COLOR_HASH_ETH: case TYPE_DSM_COLOR_ETH: case TYPE_COLOR_ETH: case TYPE_ETH: packet_len = ntohs(header->wlen); packet_len -= (pd->dag_fcs_bits >> 3); caplen = rlen - dag_record_size - 2; /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } dp += 2; break; case TYPE_COLOR_HASH_POS: case TYPE_DSM_COLOR_HDLC_POS: case TYPE_COLOR_HDLC_POS: case TYPE_HDLC_POS: packet_len = ntohs(header->wlen); packet_len -= (pd->dag_fcs_bits >> 3); caplen = rlen - dag_record_size; /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } break; case TYPE_COLOR_MC_HDLC_POS: case TYPE_MC_HDLC: packet_len = ntohs(header->wlen); packet_len -= (pd->dag_fcs_bits >> 3); caplen = rlen - dag_record_size - 4; /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } /* jump the MC_HDLC_HEADER */ dp += 4; #ifdef DLT_MTP2_WITH_PHDR if (p->linktype == DLT_MTP2_WITH_PHDR) { /* Add the MTP2 Pseudo Header */ caplen += MTP2_HDR_LEN; packet_len += MTP2_HDR_LEN; TempPkt[MTP2_SENT_OFFSET] = 0; TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN; *(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01); *(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff); memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen); dp = TempPkt; } #endif break; case TYPE_IPV4: case TYPE_IPV6: packet_len = ntohs(header->wlen); caplen = rlen - dag_record_size; /* Skip over extension headers */ caplen -= (8 * num_ext_hdr); if (caplen > packet_len) { caplen = packet_len; } break; /* These types have no matching 'native' DLT, but can be used with DLT_ERF above */ case TYPE_MC_RAW: case TYPE_MC_RAW_CHANNEL: case TYPE_IP_COUNTER: case TYPE_TCP_FLOW_COUNTER: case TYPE_INFINIBAND: case TYPE_RAW_LINK: case TYPE_INFINIBAND_LINK: default: /* Unhandled ERF type. * Ignore rather than generating error */ continue; } /* switch type */ } /* ERF encapsulation */