#include #include #include #include #include #include #include #include #include #include #include #include #include #include "mapi.h" #include "mapidrv.h" #include "mapidlib.h" #include "dagnew.h" #include "dagapi.h" #include "mapidevices.h" #include "flist.h" #include "debug.h" #define DAGSTR "dag" #define BUFSIZE 131072 __attribute__ ((constructor)) void init (); __attribute__ ((destructor)) void fini (); typedef struct dag_instance { pthread_attr_t th_attr; pthread_t th_proc; int dagfd; 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; int active; //Workaround for possible race condition when deleting a driver } dag_instance_t; flist_t *devlist; /* for mapidlib errorcode */ int mapidrv_get_errno(int devid,int fd) { dag_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) { dag_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) { dag_instance_t *i=malloc(sizeof(dag_instance_t)); i->name=strdup(devname); i->id=devid; i->dagfd=-1; i->file=file; i->th_proc=0; i->hwinfo.offline=0; i->hwinfo.gflist=gflist; i->offline_status = olstatus; i->active=1; 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) { dag_instance_t *i=flist_remove(devlist,devid,FLIST_LEAVE_DATA); if (i!=NULL) { int err=0; i->active=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 ((err=pthread_cancel(i->th_proc))!=0) { if (!(i->hwinfo.offline==1 && 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 (i->hwinfo.offline==0) { if (i->dagfd >= 0) { dag_stop(i->dagfd); dag_close(i->dagfd); DEBUG_CMD(printf("Closed dag device [%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, dag_instance_t *i) { unsigned c = 0; int rlen = 0; dag_record_t *rec; unsigned char *packet; mapid_pkthdr_t mhdr; rec = (dag_record_t *) buf; rlen = ntohs (rec->rlen); if(!i->active) return len; while (c + rlen < len && i->active) { char *p = buf; buf = p + rlen; c += rlen; if (rec->flags.trunc) WARNING_CMD(fprintf (stderr, "Warning: buffer overflow [%s:%d]\n",__FILE__,__LINE__)); packet=(unsigned char*)rec+18; mhdr.caplen=ntohs(rec->rlen); mhdr.wlen=ntohs(rec->wlen)-4; mhdr.ts=rec->ts; mhdr.ifindex=rec->flags.iface; mapid_process_pkt(&i->mapidlib,(unsigned char*)rec,packet,&mhdr); // if(c+sizeof(dag_record_t)>len-sizeof(dag_record_t)*2) //break; rec = (dag_record_t *) buf; rlen = ntohs (rec->rlen); i->hwinfo.pkts++; } return len - c; } static unsigned process_pkts_offline(void *buf,unsigned len, dag_instance_t *i) { unsigned c = 0; int rlen = 0; dag_record_t *rec; unsigned char *packet; mapid_pkthdr_t mhdr; rec = (dag_record_t *) buf; rlen = ntohs (rec->rlen); while (c + rlen <= len && rlen!=0) { char *p = buf; buf = p + rlen; c += rlen; if (rec->flags.trunc) WARNING_CMD(fprintf (stderr, "Warning: buffer overflow [%s:%d]\n",__FILE__,__LINE__)); packet=(unsigned char*)rec+18; mhdr.caplen=ntohs(rec->rlen); mhdr.wlen=ntohs(rec->wlen)-4; mhdr.ts=rec->ts; mhdr.ifindex=rec->flags.iface; mapid_process_pkt(&i->mapidlib,(unsigned char*)rec,packet,&mhdr); // if(c+sizeof(dag_record_t)>len-sizeof(dag_record_t)*2) //break; rec = (dag_record_t *) buf; rlen = ntohs (rec->rlen); i->hwinfo.pkts++; } return len - c; } static void mapidrv_offline_proc_loop(int devid) { char buf[BUFSIZE]; char *b=buf; int left=0,c; dag_instance_t *i=flist_get(devlist,devid); int err; *(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; } c=read(i->file,b,BUFSIZE); while(c>0) { left=process_pkts_offline(buf,c+left,i); //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); DEBUG_CMD(printf("Finished reading file [%s:%d], pkts: %llu\n",__FILE__,__LINE__,i->hwinfo.pkts)); *(i->offline_status) = DEVICE_FINISHED; } static void mapidrv_proc_loop (int devid) { unsigned bottom = 0, top, diff; dag_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) { top = dag_offset (i->dagfd, &bottom, 0); diff = top - bottom; bottom = top - process_pkts (((char *) i->buf + bottom), diff,i); } } int mapidrv_read_results (int devid,int fd, int fid, mapid_result_t** result) { dag_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) { dag_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) { dag_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) { dag_instance_t *i=flist_get(devlist,devid); *devtype=MAPI_DEVICE_DAG; i->hwinfo.offline=4; if(format==MFF_DAG_ERF) { //This should be read from the file i->hwinfo.link_type=DLT_EN10MB; i->hwinfo.cap_length=1500; i->hwinfo.devtype=MAPI_DEVICE_DAG; 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) { volatile uint8_t *dagiom; volatile daggpp_t *gpp; dag_instance_t *i; unsigned slen=0; dag_reg_t *regs; uint32_t regn, gpp_base; dag_reg_t result[DAG_REG_MAX_ENTRIES]; if(devid<0) { dag_instance_t *i=flist_get(devlist,devid); *devtype=MAPI_DEVICE_DAG; i->hwinfo.offline=1; //This should be read from the file i->hwinfo.link_type=DLT_EN10MB; i->hwinfo.cap_length=1500; i->hwinfo.devtype=MAPI_DEVICE_DAG; 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; } i=flist_get(devlist,devid); i->hwinfo.offline=0; *devtype=MAPI_DEVICE_DAG; //Open device if it is not already open if (i->dagfd < 0) { if ((i->dagfd = dag_open (i->name)) < 0) { ERROR_CMD(fprintf (stderr, "dag_open %s: %s [%s:%d]\n", i->name, strerror (errno),__FILE__,__LINE__)); return DAGDRV_OPEN_ERR; } i->hwinfo.cap_length=0; regs = dag_regs (i->dagfd); regn = 0; if ((dag_reg_table_find(regs, 0, DAG_REG_GPP, result, ®n)) || (!regn)) gpp_base = 0; else gpp_base = DAG_REG_ADDR(*result); if (gpp_base) { /* memory mapped area */ dagiom = dag_iom(i->dagfd); if (((*(volatile uint32_t *)dagiom >> 16) & 0xff) != 0x03) { gpp = (daggpp_t *) (dagiom + gpp_base); /* WARNING: race */ slen = gpp->snaplen; } } i->hwinfo.cap_length=slen; if (i->hwinfo.cap_length==0) { WARNING_CMD(printf("WARNING: Could not get info hardware-info, using default =1500 [%s:%d]\n",__FILE__,__LINE__)); i->hwinfo.cap_length=1500; } switch (dag_linktype(i->dagfd)) { default: case TYPE_ETH: i->hwinfo.link_type=DLT_EN10MB; break; case TYPE_ATM: i->hwinfo.link_type=DLT_ATM_RFC1483; break; /* can be both DLT_CHDLC and DLT_PPP_SERIAL?? */ case TYPE_HDLC_POS: i->hwinfo.link_type=DLT_CHDLC; break; } DEBUG_CMD(printf("From dag HW: cap_length=%u linktype=%u [%s:%d]\n",i->hwinfo.cap_length,i->hwinfo.link_type,__FILE__,__LINE__)); i->hwinfo.devtype=MAPI_DEVICE_DAG; i->hwinfo.devid=i->id; i->hwinfo.pkts=0; //Initialize DAG buffer if ((i->buf = dag_mmap (i->dagfd)) == MAP_FAILED) { ERROR_CMD(fprintf (stderr, "dag_mmap failed [%s:%d]\n",__FILE__,__LINE__)); return DAGDRV_MMAP_ERR; } if (dag_start (i->dagfd) < 0) { ERROR_CMD(fprintf (stderr, "dag_start failed [%s:%d]\n",__FILE__,__LINE__)); return DAGDRV_START_ERR; } //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 DAGDRV_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) { dag_instance_t *i=flist_get(devlist,devid); if(i==NULL) return -1; return mapid_connect(&i->mapidlib,fd); } int mapidrv_start_offline_device( int devid) { dag_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 DAGDRV_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 DAGDRV_PTHR_ERR; } } return 0; } int mapidrv_close_flow (int devid,int fd) { dag_instance_t *i=flist_get(devlist,devid); return mapid_close_flow(&i->mapidlib,fd); } int mapidrv_load_library(MAPI_UNUSED int devid,char* lib) { return mapid_load_library(lib); } 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 mapid_get_lib_name(libnumber); } __attribute__ ((constructor)) void init () { devlist=malloc(sizeof(flist_t)); flist_init(devlist); DEBUG_CMD(printf ("DAG driver loaded [%s:%d]\n",__FILE__,__LINE__)); } __attribute__ ((destructor)) void fini () { free(devlist); DEBUG_CMD(printf ("DAG driver unloaded [%s:%d]\n",__FILE__,__LINE__)); }