#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mapi.h" #include "mapidrv.h" #include "mapidlib.h" #include "mapidevices.h" #include "flist.h" #include "debug.h" #define ETHSTR "eth" #define LOSTR "lo" #define BUFSIZE 32768 #define NIC_PKTCAP_LEN 1500 __attribute__ ((constructor)) void init (); __attribute__ ((destructor)) void fini (); typedef struct nic_instance { pthread_attr_t th_attr; pthread_t th_proc; pcap_t *pcap; int eventset; void *buf; int file; char *name; int id; mapi_offline_device_status_t *offline_status; mapid_hw_info_t hwinfo; mapidlib_instance_t mapidlib; } nic_instance_t; flist_t *devlist; /* for mapidlib errorcode */ int mapidrv_get_errno(int devid,int fd) { nic_instance_t *i=flist_get(devlist,devid); return mapid_get_errno(&i->mapidlib,fd); } int mapidrv_apply_function (int devid,int fd, char* function, mapiFunctArg *fargs) { nic_instance_t *i=flist_get(devlist,devid); return mapid_apply_function(&i->mapidlib,fd, function, fargs); } int mapidrv_add_device(mapi_offline_device_status_t* olstatus,char *devname, int file,int devid, global_function_list_t *gflist) { nic_instance_t *i=malloc(sizeof(nic_instance_t)); i->name=strdup(devname); i->id=devid; i->pcap=NULL; i->file=file; i->th_proc=0; i->hwinfo.offline=0; i->hwinfo.gflist=gflist; i->offline_status = olstatus; if(devid<0) i->hwinfo.offline=1; DEBUG_CMD(printf("Added device %d: %s [%s:%d]\n",devid,devname,__FILE__,__LINE__)); flist_append(devlist,devid,i); mapid_init(&i->mapidlib); return 0; } int mapidrv_delete_device(int devid) { nic_instance_t *i=flist_remove(devlist,devid,FLIST_LEAVE_DATA); if (i!=NULL) { int err=0; // if (i->th_proc && pthread_equal(i->th_proc, pthread_self())==0) { // DEBUG_CMD(printf("Calling thread != th_proc (%lu != %lu), canceling [%s:%d]\n",i->th_proc,pthread_self(),__FILE__,__LINE__)); fflush(stdout); if(i->th_proc) { if ((err=pthread_cancel(i->th_proc))!=0) { if (!(i->hwinfo.offline>2 && err==ESRCH)) { WARNING_CMD(printf("Could not cancel thread for devid %d (%s) [%s:%d]\n",devid,strerror(err),__FILE__,__LINE__)); fflush(stdout); } } if ((err=pthread_join(i->th_proc,NULL))!=0) { if (!(i->hwinfo.offline==1 && err==ESRCH)) { WARNING_CMD(printf("Could not join thread for devid %d (%s) [%s:%d]\n",devid,strerror(err),__FILE__,__LINE__)); fflush(stdout); } } if ((err=pthread_attr_destroy(&i->th_attr))!=0) WARNING_CMD(printf("Could not destroy threads attribute object for devid %d (%s) [%s:%d]\n",devid,strerror(err),__FILE__,__LINE__)); } if (i->hwinfo.offline==0) { if (i->pcap != NULL) { pcap_close(i->pcap); DEBUG_CMD(printf("Closed pcap handle [%s:%d]\n",__FILE__,__LINE__)); } } else { if (i->file) { close(i->file); DEBUG_CMD(printf("Closed file [%s:%d]\n",__FILE__,__LINE__)); } } mapid_destroy(&i->mapidlib); free(i->name); if(i->offline_status!=NULL) *(i->offline_status) = DEVICE_DELETED; free(i); } return 0; } static unsigned process_pkts(void *buf,unsigned len, nic_instance_t *i,MAPI_UNUSED int devid, int last) { unsigned c = 0; int rlen = 0; struct pcap_pkthdr *rec; unsigned char *packet; mapid_pkthdr_t mhdr; rec = (struct pcap_pkthdr *) buf; rlen = rec->caplen+sizeof(struct pcap_pkthdr); while (c + rlen <= len) { char *p = buf; buf = p + rlen; c += rlen; mhdr.caplen = rec->caplen; mhdr.ifindex = 0; mhdr.wlen = rec->len; mhdr.ts = (((unsigned long long)rec->ts.tv_sec)<<32)+((rec->ts.tv_usec*4295) & 0xffffffff); //TODO: Need to check accuracy of timestamp. Rounding errors? // increase counter for packets seen so far i->hwinfo.pkts++; packet=(unsigned char*)rec+(sizeof(struct pcap_pkthdr)); if(lastlen) i->hwinfo.offline=3; mapid_process_pkt(&i->mapidlib,(unsigned char*)rec,packet,&mhdr); // if(c+sizeof(dag_record_t)>len-sizeof(dag_record_t)*2) //break; rec = (struct pcap_pkthdr *) buf; rlen = rec->caplen+sizeof(struct pcap_pkthdr); } return len - c; } static void mapidrv_offline_proc_loop(int devid) { char buf[BUFSIZE]; char *b=buf; int left=0,c; nic_instance_t *i=flist_get(devlist,devid); int err; struct pcap_file_header head; *(i->offline_status) = DEVICE_READING; if ((err=pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) != 0) { ERROR_CMD(fprintf(stderr, "pthread_setcanceltype failed (%s) [%s:%d]\n",strerror(err),__FILE__,__LINE__)); return; } if ((err=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) != 0) { ERROR_CMD(fprintf(stderr, "pthread_setcancelstate (%s) failed [%s:%d]\n",strerror(err),__FILE__,__LINE__)); return; } //Read pcap header c=read(i->file,&head,sizeof(struct pcap_file_header)); c=read(i->file,b,BUFSIZE); while(c>0) { left=process_pkts(buf,c+left,i,devid,c); //Copy last bytes to beginning of buffer memcpy(buf,b+c-left,left); b=buf+left; c=read(i->file,b,BUFSIZE-left); } mapid_finished(&i->mapidlib); *(i->offline_status) = DEVICE_FINISHED; DEBUG_CMD(printf("Finished reading file, pkts %lld [%s:%d]\n",i->hwinfo.pkts,__FILE__,__LINE__)); } static void mapidrv_proc_loop (int devid) { u_char *packet; struct pcap_pkthdr phdr; mapid_pkthdr_t mhdr; nic_instance_t *i=flist_get(devlist,devid); int err; if ((err=pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) != 0) { ERROR_CMD(fprintf(stderr, "pthread_setcanceltype failed (%s) [%s:%d]\n",strerror(err),__FILE__,__LINE__)); return; } if ((err=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) != 0) { ERROR_CMD(fprintf(stderr, "pthread_setcancelstate (%s) failed [%s:%d]\n",strerror(err),__FILE__,__LINE__)); return; } while (1) { while( (packet = (u_char *)pcap_next(i->pcap,&phdr)) == NULL ); // Transform header // This is only for backward compatibility mhdr.caplen = phdr.caplen; mhdr.wlen = phdr.len; mhdr.ts = (((unsigned long long)phdr.ts.tv_sec)<<32)+((phdr.ts.tv_usec*4295) & 0xffffffff); // increase counter for packets seen so far i->hwinfo.pkts++; // Process packet mapid_process_pkt(&i->mapidlib,packet,packet,&mhdr); } } int mapidrv_read_results (int devid,int fd, int fid, mapid_result_t** result) { nic_instance_t *i=flist_get(devlist,devid); return mapid_read_results(&i->mapidlib,fd,fid,result); } mapid_funct_info_t* mapidrv_get_flow_functions(int devid,int fd) { nic_instance_t *i=flist_get(devlist,devid); return mapid_get_flow_functions(&i->mapidlib,fd); } int mapidrv_get_flow_info(int devid,int fd,mapi_flow_info_t *info) { nic_instance_t *i=flist_get(devlist,devid); return mapid_get_flow_info(&i->mapidlib,fd,info); } int mapidrv_create_offline_flow (int devid, int format,int fd,char **devtype) { nic_instance_t *i=flist_get(devlist,devid); *devtype=MAPI_DEVICE_NIC; i->hwinfo.offline=4; if(format==MFF_PCAP) { //This should be read from the file i->hwinfo.link_type=DLT_EN10MB; i->hwinfo.cap_length=1514; i->hwinfo.devtype=MAPI_DEVICE_NIC; i->hwinfo.devid=i->id; i->hwinfo.pkts=0; DEBUG_CMD(printf("Reading from trace file: %s [%s:%d]\n",i->name,__FILE__,__LINE__)); return mapid_add_flow(&i->mapidlib,fd,&i->hwinfo,NULL); } return 0; } int mapidrv_create_flow (int devid, int fd, char **devtype) { nic_instance_t *i=flist_get(devlist,devid); char errbuf[PCAP_ERRBUF_SIZE]; //i->hwinfo.offline=0; *devtype=MAPI_DEVICE_NIC; if(i->hwinfo.offline > 0) { //This should be read from the file i->hwinfo.link_type=DLT_EN10MB; i->hwinfo.cap_length=1500; i->hwinfo.devtype=MAPI_DEVICE_NIC; i->hwinfo.devid=i->id; i->hwinfo.pkts=0; DEBUG_CMD(printf("Reading from trace file: %s [%s:%d]\n",i->name,__FILE__,__LINE__)); return mapid_add_flow(&i->mapidlib,fd,&i->hwinfo,NULL); } //Open device if it is not already open if (i->pcap==NULL) { if( (i->pcap = pcap_open_live(i->name,NIC_PKTCAP_LEN,1,0,errbuf)) == NULL ) { ERROR_CMD(fprintf(stderr,"pcap_open_live: %s [%s:%d]\n",errbuf,__FILE__,__LINE__)); return PCAP_OPEN_ERR; } i->hwinfo.link_type = pcap_datalink(i->pcap); i->hwinfo.cap_length = pcap_snapshot(i->pcap); i->hwinfo.devid=i->id; i->hwinfo.pkts=0; i->hwinfo.devtype=MAPI_DEVICE_NIC; //Start processing thread if (pthread_attr_init (&i->th_attr) != 0) { ERROR_CMD(fprintf (stderr, "pthread_attr_init failed [%s:%d]\n",__FILE__,__LINE__)); return NICDRV_PTHR_ERR; } if (pthread_create (&i->th_proc, &i->th_attr, (void *) mapidrv_proc_loop, (void*)devid) != 0) { ERROR_CMD(fprintf (stderr, "pthread_create failed [%s:%d]\n",__FILE__,__LINE__)); return DAGDRV_PTHR_ERR; } } return mapid_add_flow(&i->mapidlib,fd,&i->hwinfo,NULL); } int mapidrv_connect (int devid,int fd) { nic_instance_t *i=flist_get(devlist,devid); int ret = mapid_connect(&i->mapidlib,fd); if(i->hwinfo.offline==4) { if (pthread_attr_init (&i->th_attr) != 0) { ERROR_CMD(fprintf (stderr, "pthread_attr_init failed [%s:%d]\n",__FILE__,__LINE__)); return NICDRV_PTHR_ERR; } if (pthread_create (&i->th_proc, &i->th_attr, (void *) mapidrv_offline_proc_loop, (void *)i->id) != 0) { ERROR_CMD(fprintf (stderr, "pthread_create failed [%s:%d]\n",__FILE__,__LINE__)); return NICDRV_PTHR_ERR; } } return ret; } int mapidrv_start_offline_device( int devid) { nic_instance_t *i = flist_get(devlist,devid); if(i->hwinfo.offline==1) { if (pthread_attr_init (&i->th_attr) != 0) { ERROR_CMD(fprintf (stderr, "pthread_attr_init failed [%s:%d]\n",__FILE__,__LINE__)); return NICDRV_PTHR_ERR; } if (pthread_create (&i->th_proc, &i->th_attr, (void *) mapidrv_offline_proc_loop, (void *)i->id) != 0) { ERROR_CMD(fprintf (stderr, "pthread_create failed [%s:%d]\n",__FILE__,__LINE__)); return NICDRV_PTHR_ERR; } } return 0; } mapi_function_def_mini_t* mapidrv_get_function_info(int libnumber,int functionnumber) { return mapid_get_function_info(libnumber, functionnumber); } unsigned char* mapidrv_get_lib_name(int libnumber) { return (unsigned char*)mapid_get_lib_name(libnumber); } int mapidrv_close_flow (int devid,int fd) { nic_instance_t *i=flist_get(devlist,devid); if(i==NULL) return -1; return mapid_close_flow(&i->mapidlib,fd); } int mapidrv_load_library(MAPI_UNUSED int devid,char* lib) { return mapid_load_library(lib); } __attribute__ ((constructor)) void init () { devlist=malloc(sizeof(flist_t)); flist_init(devlist); DEBUG_CMD(printf ("NIC driver loaded [%s:%d]\n",__FILE__,__LINE__)); } __attribute__ ((destructor)) void fini () { free(devlist); DEBUG_CMD(printf ("NIC driver unloaded [%s:%d]\n",__FILE__,__LINE__)); }