From 446242760ec28d8a7634115ac07f647f057e2ed5 Mon Sep 17 00:00:00 2001 From: mlaier Date: Tue, 16 Oct 2007 02:02:02 +0000 Subject: Import of libpcap v0.9.8 --- contrib/libpcap/pcap-dag.c | 363 ++++++++++++++++++++++++++++++--------------- 1 file changed, 242 insertions(+), 121 deletions(-) (limited to 'contrib/libpcap/pcap-dag.c') diff --git a/contrib/libpcap/pcap-dag.c b/contrib/libpcap/pcap-dag.c index ee48283..3ef2508 100644 --- a/contrib/libpcap/pcap-dag.c +++ b/contrib/libpcap/pcap-dag.c @@ -17,7 +17,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.21.2.3 2005/07/10 22:09:34 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.21.2.7 2007/06/22 06:43:58 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -46,11 +46,21 @@ struct rtentry; /* declarations in */ #include "dagnew.h" #include "dagapi.h" -#define MIN_DAG_SNAPLEN 12 -#define MAX_DAG_SNAPLEN 2040 #define ATM_CELL_SIZE 52 #define ATM_HDR_SIZE 4 +/* + * A header containing additional MTP information. + */ +#define MTP2_SENT_OFFSET 0 /* 1 byte */ +#define MTP2_ANNEX_A_USED_OFFSET 1 /* 1 byte */ +#define MTP2_LINK_NUMBER_OFFSET 2 /* 2 bytes */ +#define MTP2_HDR_LEN 4 /* length of the header */ + +#define MTP2_ANNEX_A_NOT_USED 0 +#define MTP2_ANNEX_A_USED 1 +#define MTP2_ANNEX_A_USED_UNKNOWN 2 + /* SunATM pseudo header */ struct sunatm_hdr { unsigned char flags; /* destination and traffic type */ @@ -70,19 +80,6 @@ static const unsigned short endian_test_word = 0x0100; #define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word)) -/* - * Swap byte ordering of unsigned long long timestamp on a big endian - * machine. - */ -#define SWAP_TS(ull) ((ull & 0xff00000000000000LL) >> 56) | \ - ((ull & 0x00ff000000000000LL) >> 40) | \ - ((ull & 0x0000ff0000000000LL) >> 24) | \ - ((ull & 0x000000ff00000000LL) >> 8) | \ - ((ull & 0x00000000ff000000LL) << 8) | \ - ((ull & 0x0000000000ff0000LL) << 24) | \ - ((ull & 0x000000000000ff00LL) << 40) | \ - ((ull & 0x00000000000000ffLL) << 56) - #ifdef DAG_ONLY /* This code is required when compiling for a DAG device only. */ @@ -93,6 +90,10 @@ static const unsigned short endian_test_word = 0x0100; #define dag_platform_finddevs pcap_platform_finddevs #endif /* DAG_ONLY */ +#define MAX_DAG_PACKET 65536 + +static unsigned char TempPkt[MAX_DAG_PACKET]; + static int dag_setfilter(pcap_t *p, struct bpf_program *fp); static int dag_stats(pcap_t *p, struct pcap_stat *ps); static int dag_set_datalink(pcap_t *p, int dlt); @@ -139,9 +140,6 @@ dag_platform_close(pcap_t *p) #endif /* HAVE_DAG_STREAMS_API */ if(dag_close(p->fd) < 0) fprintf(stderr,"dag_close: %s\n", strerror(errno)); -#ifdef linux - free(p->md.device); -#endif } delete_pcap_dag(p); /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */ @@ -222,7 +220,7 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) * 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, (void**)&(p->md.dag_mem_bottom)); + 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); @@ -282,8 +280,14 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) p->md.dag_mem_bottom += rlen; switch(header->type) { - case TYPE_AAL5: 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) { @@ -299,10 +303,7 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) dp+=4; } #endif - if (header->type == TYPE_AAL5) { - packet_len = ntohs(header->wlen); - caplen = rlen - dag_record_size; - } else if(header->type == TYPE_ATM) { + if (header->type == TYPE_ATM) { caplen = packet_len = ATM_CELL_SIZE; } if (p->linktype == DLT_SUNATM) { @@ -326,6 +327,9 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } break; +#ifdef TYPE_DSM_COLOR_ETH + case TYPE_DSM_COLOR_ETH: +#endif #ifdef TYPE_COLOR_ETH case TYPE_COLOR_ETH: #endif @@ -338,6 +342,9 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } dp += 2; break; +#ifdef TYPE_DSM_COLOR_HDLC_POS + case TYPE_DSM_COLOR_HDLC_POS: +#endif #ifdef TYPE_COLOR_HDLC_POS case TYPE_COLOR_HDLC_POS: #endif @@ -349,6 +356,9 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) caplen = packet_len; } break; +#ifdef TYPE_COLOR_MC_HDLC_POS + case TYPE_COLOR_MC_HDLC_POS: +#endif #ifdef TYPE_MC_HDLC case TYPE_MC_HDLC: packet_len = ntohs(header->wlen); @@ -357,9 +367,27 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) if (caplen > packet_len) { caplen = packet_len; } + /* jump the MC_HDLC_HEADER */ dp += 4; + 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; + } break; #endif + default: + /* Unhandled ERF type. + * Ignore rather than generating error + */ + continue; } if (caplen > p->snapshot) @@ -377,6 +405,21 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) case TYPE_COLOR_ETH: break; #endif +#ifdef TYPE_DSM_COLOR_HDLC_POS + /* in this type the color value overwrites the lctr */ + case TYPE_DSM_COLOR_HDLC_POS: + break; +#endif +#ifdef TYPE_DSM_COLOR_ETH + /* in this type the color value overwrites the lctr */ + case TYPE_DSM_COLOR_ETH: + break; +#endif +#ifdef TYPE_COLOR_MC_HDLC_POS + case TYPE_COLOR_MC_HDLC_POS: + break; +#endif + default: if (header->lctr) { if (p->md.stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) { @@ -394,7 +437,7 @@ dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) register unsigned long long ts; if (IS_BIGENDIAN()) { - ts = SWAP_TS(header->ts); + ts = SWAPLL(header->ts); } else { ts = header->ts; } @@ -445,6 +488,9 @@ dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_) * cards are always promiscuous. The to_ms parameter is also ignored as it is * not supported in hardware. * + * snaplen is now also ignored, until we get per-stream slen support. Set + * slen with approprite DAG tool BEFORE pcap_open_live(). + * * See also pcap(3). */ pcap_t * @@ -455,7 +501,7 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu char *s; int n; daginf_t* daginf; - char * newDev; + char * newDev = NULL; #ifdef HAVE_DAG_STREAMS_API uint32_t mindata; struct timeval maxwait; @@ -478,9 +524,12 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu memset(handle, 0, sizeof(*handle)); - newDev = (char *)malloc(strlen(device) + 16); - #ifdef HAVE_DAG_STREAMS_API + newDev = (char *)malloc(strlen(device) + 16); + if (newDev == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); + goto fail; + } /* Parse input name to get dag device and stream number if provided */ if (dag_parse_name(device, newDev, strlen(device) + 16, &handle->md.dag_stream) < 0) { @@ -494,18 +543,15 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu goto fail; } #else - if (strstr(device, "/dev") == NULL) { - newDev[0] = '\0'; - strcat(newDev, "/dev/"); - strcat(newDev,device); + if (strncmp(device, "/dev/", 5) != 0) { + newDev = (char *)malloc(strlen(device) + 5); + if (newDev == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "Can't allocate string for device name: %s\n", pcap_strerror(errno)); + goto fail; + } + strcpy(newDev, "/dev/"); + strcat(newDev, device); device = newDev; - } else { - device = strdup(device); - } - - if (device == NULL) { - snprintf(ebuf, PCAP_ERRBUF_SIZE, "str_dup: %s\n", pcap_strerror(errno)); - goto fail; } #endif /* HAVE_DAG_STREAMS_API */ @@ -519,7 +565,7 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu /* Open requested stream. Can fail if already locked or on error */ if (dag_attach_stream(handle->fd, handle->md.dag_stream, 0, 0) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_attach_stream: %s\n", pcap_strerror(errno)); - goto fail; + goto failclose; } /* Set up default poll parameters for stream @@ -528,7 +574,7 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu if (dag_get_stream_poll(handle->fd, handle->md.dag_stream, &mindata, &maxwait, &poll) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_get_stream_poll: %s\n", pcap_strerror(errno)); - goto fail; + goto faildetach; } /* Amount of data to collect in Bytes before calling callbacks. @@ -546,18 +592,25 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu if (dag_set_stream_poll(handle->fd, handle->md.dag_stream, mindata, &maxwait, &poll) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_set_stream_poll: %s\n", pcap_strerror(errno)); - goto fail; + goto faildetach; } #else if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) { snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno)); - goto fail; + goto failclose; } #endif /* HAVE_DAG_STREAMS_API */ + /* XXX Not calling dag_configure() to set slen; this is unsafe in + * multi-stream environments as the gpp config is global. + * Once the firmware provides 'per-stream slen' this can be supported + * again via the Config API without side-effects */ +#if 0 /* set the card snap length to the specified snaplen parameter */ + /* This is a really bad idea, as different cards have different + * valid slen ranges. Should fix in Config API. */ if (snaplen == 0 || snaplen > MAX_DAG_SNAPLEN) { snaplen = MAX_DAG_SNAPLEN; } else if (snaplen < MIN_DAG_SNAPLEN) { @@ -568,18 +621,19 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu if(dag_configure(handle->fd, conf) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno)); - goto fail; + goto faildetach; } - +#endif + #ifdef HAVE_DAG_STREAMS_API if(dag_start_stream(handle->fd, handle->md.dag_stream) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start_stream %s: %s\n", device, pcap_strerror(errno)); - goto fail; + goto faildetach; } #else if(dag_start(handle->fd) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno)); - goto fail; + goto failclose; } #endif /* HAVE_DAG_STREAMS_API */ @@ -607,7 +661,7 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu } else { snprintf(ebuf, PCAP_ERRBUF_SIZE, "pcap_open_live %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n); - goto fail; + goto failstop; } } @@ -617,14 +671,14 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu handle->linktype = -1; if (dag_get_datalink(handle) < 0) { strcpy(ebuf, handle->errbuf); - goto fail; + goto failstop; } handle->bufsize = 0; if (new_pcap_dag(handle) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno)); - goto fail; + goto failstop; } /* @@ -632,13 +686,9 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu */ handle->selectable_fd = -1; -#ifdef linux - handle->md.device = (char *)device; - handle->md.timeout = to_ms; -#else - free((char *)device); - device = NULL; -#endif + if (newDev != NULL) { + free((char *)newDev); + } handle->read_op = dag_read; handle->inject_op = dag_inject; @@ -649,9 +699,38 @@ dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebu handle->setnonblock_op = dag_setnonblock; handle->stats_op = dag_stats; handle->close_op = dag_platform_close; - + handle->md.stat.ps_drop = 0; + handle->md.stat.ps_recv = 0; return handle; +#ifdef HAVE_DAG_STREAMS_API +failstop: + if (handle != NULL) { + if (dag_stop_stream(handle->fd, handle->md.dag_stream) < 0) + fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno)); + } + +faildetach: + if (handle != NULL) { + if (dag_detach_stream(handle->fd, handle->md.dag_stream) < 0) + fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno)); + } +#else +failstop: + if (handle != NULL) { + if (dag_stop(p->fd) < 0) + fprintf(stderr,"dag_stop: %s\n", strerror(errno)); + } +#endif /* HAVE_DAG_STREAMS_API */ + +failclose: + if (handle != NULL) { + if (dag_close(handle->fd) < 0) + fprintf(stderr,"dag_close: %s\n", strerror(errno)); + } + if (handle != NULL) + delete_pcap_dag(handle); + fail: if (newDev != NULL) { free((char *)newDev); @@ -806,81 +885,123 @@ dag_setnonblock(pcap_t *p, int nonblock, char *errbuf) static int dag_get_datalink(pcap_t *p) { - int daglinktype; + int index=0; + uint8_t types[255]; - if (p->dlt_list == NULL && (p->dlt_list = malloc(2*sizeof(*(p->dlt_list)))) == NULL) { + memset(types, 0, 255); + + if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) { (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); return (-1); } + p->linktype = 0; + +#ifdef HAVE_DAG_GET_ERF_TYPES + /* Get list of possible ERF types for this card */ + if (dag_get_erf_types(p->fd, types, 255) < 0) { + snprintf(p->errbuf, sizeof(p->errbuf), "dag_get_erf_types: %s", pcap_strerror(errno)); + return (-1); + } + + while (types[index]) { +#else /* Check the type through a dagapi call. */ - daglinktype = dag_linktype(p->fd); + types[index] = dag_linktype(p->fd); - switch(daglinktype) { + { +#endif + switch(types[index]) { - case TYPE_HDLC_POS: - case TYPE_COLOR_HDLC_POS: - if (p->dlt_list != NULL) { - p->dlt_count = 2; - p->dlt_list[0] = DLT_CHDLC; - p->dlt_list[1] = DLT_PPP_SERIAL; - p->dlt_list[2] = DLT_FRELAY; - } - p->linktype = DLT_CHDLC; - break; + case TYPE_HDLC_POS: +#ifdef TYPE_COLOR_HDLC_POS + case TYPE_COLOR_HDLC_POS: +#endif +#ifdef TYPE_DSM_COLOR_HDLC_POS + case TYPE_DSM_COLOR_HDLC_POS: +#endif + if (p->dlt_list != NULL) { + p->dlt_list[index++] = DLT_CHDLC; + p->dlt_list[index++] = DLT_PPP_SERIAL; + p->dlt_list[index++] = DLT_FRELAY; + } + if(!p->linktype) + p->linktype = DLT_CHDLC; + break; - case TYPE_ETH: - case TYPE_COLOR_ETH: - /* - * This is (presumably) a real Ethernet capture; give it a - * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so - * that an application can let you choose it, in case you're - * capturing DOCSIS traffic that a Cisco Cable Modem - * Termination System is putting out onto an Ethernet (it - * doesn't put an Ethernet header onto the wire, it puts raw - * DOCSIS frames out on the wire inside the low-level - * Ethernet framing). - */ - if (p->dlt_list != NULL) { - p->dlt_count = 2; - p->dlt_list[0] = DLT_EN10MB; - p->dlt_list[1] = DLT_DOCSIS; - } - p->linktype = DLT_EN10MB; - break; - - case TYPE_AAL5: - case TYPE_ATM: - case TYPE_MC_ATM: - case TYPE_MC_AAL5: - if (p->dlt_list != NULL) { - p->dlt_count = 2; - p->dlt_list[0] = DLT_ATM_RFC1483; - p->dlt_list[1] = DLT_SUNATM; - } - p->linktype = DLT_ATM_RFC1483; - break; - - case TYPE_MC_HDLC: - if (p->dlt_list != NULL) { - p->dlt_count = 4; - p->dlt_list[0] = DLT_CHDLC; - p->dlt_list[1] = DLT_PPP_SERIAL; - p->dlt_list[2] = DLT_FRELAY; - p->dlt_list[3] = DLT_MTP2; - } - p->linktype = DLT_CHDLC; - break; + case TYPE_ETH: +#ifdef TYPE_COLOR_ETH + case TYPE_COLOR_ETH: +#endif +#ifdef TYPE_DSM_COLOR_ETH + case TYPE_DSM_COLOR_ETH: +#endif + /* + * This is (presumably) a real Ethernet capture; give it a + * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so + * that an application can let you choose it, in case you're + * capturing DOCSIS traffic that a Cisco Cable Modem + * Termination System is putting out onto an Ethernet (it + * doesn't put an Ethernet header onto the wire, it puts raw + * DOCSIS frames out on the wire inside the low-level + * Ethernet framing). + */ + if (p->dlt_list != NULL) { + p->dlt_list[index++] = DLT_EN10MB; + p->dlt_list[index++] = DLT_DOCSIS; + } + if(!p->linktype) + p->linktype = DLT_EN10MB; + break; - case TYPE_LEGACY: - p->linktype = DLT_NULL; - break; + case TYPE_ATM: +#ifdef TYPE_AAL5 + case TYPE_AAL5: +#endif +#ifdef TYPE_MC_ATM + case TYPE_MC_ATM: +#endif +#ifdef TYPE_MC_AAL5 + case TYPE_MC_AAL5: +#endif + if (p->dlt_list != NULL) { + p->dlt_list[index++] = DLT_ATM_RFC1483; + p->dlt_list[index++] = DLT_SUNATM; + } + if(!p->linktype) + p->linktype = DLT_ATM_RFC1483; + break; - default: - snprintf(p->errbuf, sizeof(p->errbuf), "unknown DAG linktype %d\n", daglinktype); - return (-1); +#ifdef TYPE_COLOR_MC_HDLC_POS + case TYPE_COLOR_MC_HDLC_POS: +#endif +#ifdef TYPE_MC_HDLC + case TYPE_MC_HDLC: + if (p->dlt_list != NULL) { + p->dlt_list[index++] = DLT_CHDLC; + p->dlt_list[index++] = DLT_PPP_SERIAL; + p->dlt_list[index++] = DLT_FRELAY; + p->dlt_list[index++] = DLT_MTP2; + p->dlt_list[index++] = DLT_MTP2_WITH_PHDR; + } + if(!p->linktype) + p->linktype = DLT_CHDLC; + break; +#endif + + case TYPE_LEGACY: + if(!p->linktype) + p->linktype = DLT_NULL; + break; + + default: + snprintf(p->errbuf, sizeof(p->errbuf), "unknown DAG linktype %d", types[index]); + return (-1); + } /* switch */ } + p->dlt_count = index; + return p->linktype; } -- cgit v1.1