diff options
Diffstat (limited to 'pcap-canusb-linux.c')
-rw-r--r-- | pcap-canusb-linux.c | 361 |
1 files changed, 200 insertions, 161 deletions
diff --git a/pcap-canusb-linux.c b/pcap-canusb-linux.c index 5abfe18ec71f6..b84f884cee971 100644 --- a/pcap-canusb-linux.c +++ b/pcap-canusb-linux.c @@ -75,20 +75,18 @@ struct CAN_Msg struct canusb_t { - libusb_context *ctx; - libusb_device_handle *dev; - char* src; - pthread_t worker; - int rdpipe, wrpipe; - volatile int* loop; + libusb_context *ctx; + libusb_device_handle *dev; + char *serial; + pthread_t worker; + int rdpipe, wrpipe; + volatile int* loop; }; static struct canusb_t canusb; static volatile int loop; - - -int canusb_platform_finddevs(pcap_if_t **alldevsp, char *err_str) +int canusb_findalldevs(pcap_if_t **alldevsp, char *err_str) { libusb_context *fdctx; libusb_device** devs; @@ -96,8 +94,15 @@ int canusb_platform_finddevs(pcap_if_t **alldevsp, char *err_str) unsigned char buf[96]; int cnt, i; - libusb_init(&fdctx); - + if (libusb_init(&fdctx) != 0) { + /* + * XXX - if this doesn't just mean "no USB file system mounted", + * perhaps we should report a real error rather than just + * saying "no CANUSB devices". + */ + return 0; + } + cnt = libusb_get_device_list(fdctx,&devs); for(i=0;i<cnt;i++) @@ -108,27 +113,27 @@ int canusb_platform_finddevs(pcap_if_t **alldevsp, char *err_str) libusb_get_device_descriptor(devs[i],&desc); if ((desc.idVendor != CANUSB_VID) || (desc.idProduct != CANUSB_PID)) - continue; //It is not, check next device + continue; //It is not, check next device //It is! libusb_device_handle *dh = NULL; if (ret = libusb_open(devs[i],&dh) == 0) { - char dev_name[30]; - char dev_descr[50]; + char dev_name[30]; + char dev_descr[50]; int n = libusb_get_string_descriptor_ascii(dh,desc.iSerialNumber,sernum,64); sernum[n] = 0; - snprintf(dev_name, 30, CANUSB_IFACE"%s", sernum); - snprintf(dev_descr, 50, "CanUSB [%s]", sernum); + snprintf(dev_name, 30, CANUSB_IFACE"%s", sernum); + snprintf(dev_descr, 50, "CanUSB [%s]", sernum); libusb_close(dh); if (pcap_add_if(alldevsp, dev_name, 0, dev_descr, err_str) < 0) { - libusb_free_device_list(devs,1); - return -1; + libusb_free_device_list(devs,1); + return -1; } } } @@ -199,144 +204,176 @@ static libusb_device_handle* canusb_opendevice(struct libusb_context *ctx, char* pcap_t * -canusb_create(const char *device, char *ebuf) +canusb_create(const char *device, char *ebuf, int *is_ours) { - pcap_t* p; - - libusb_init(&canusb.ctx); - - p = pcap_create_common(device, ebuf); - if (p == NULL) - return (NULL); - - memset(&canusb, 0x00, sizeof(canusb)); - - - p->activate_op = canusb_activate; - - canusb.src = strdup(p->opt.source); - return (p); + const char *cp; + char *cpend; + long devnum; + pcap_t* p; + + libusb_init(&canusb.ctx); + + /* Does this look like a DAG device? */ + cp = strrchr(device, '/'); + if (cp == NULL) + cp = device; + /* Does it begin with "canusb"? */ + if (strncmp(cp, "canusb", 6) != 0) { + /* Nope, doesn't begin with "canusb" */ + *is_ours = 0; + return NULL; + } + /* Yes - is "canusb" followed by a number? */ + cp += 6; + devnum = strtol(cp, &cpend, 10); + if (cpend == cp || *cpend != '\0') { + /* Not followed by a number. */ + *is_ours = 0; + return NULL; + } + if (devnum < 0) { + /* Followed by a non-valid number. */ + *is_ours = 0; + return NULL; + } + + /* OK, it's probably ours. */ + *is_ours = 1; + + p = pcap_create_common(device, ebuf); + if (p == NULL) + return (NULL); + + memset(&canusb, 0x00, sizeof(canusb)); + + p->activate_op = canusb_activate; + + return (p); } static void* canusb_capture_thread(struct canusb_t *canusb) { - struct libusb_context *ctx; - libusb_device_handle *dev; - - int i, n; - struct - { - uint8_t rxsz, txsz; - } status; + struct libusb_context *ctx; + libusb_device_handle *dev; + int i, n; + struct + { + uint8_t rxsz, txsz; + } status; + char *serial; - libusb_init(&ctx); + libusb_init(&ctx); - char *serial = canusb->src + strlen(CANUSB_IFACE); - dev = canusb_opendevice(ctx, serial); + serial = canusb->serial; + dev = canusb_opendevice(ctx, serial); - fcntl(canusb->wrpipe, F_SETFL, O_NONBLOCK); + fcntl(canusb->wrpipe, F_SETFL, O_NONBLOCK); - while(*canusb->loop) - { - int sz, ret; - struct CAN_Msg msg; + while(*canusb->loop) + { + int sz, ret; + struct CAN_Msg msg; - libusb_interrupt_transfer(dev, 0x81, (unsigned char*)&status, sizeof(status), &sz, 100); - //HACK!!!!! -> drop buffered data, read new one by reading twice. - ret = libusb_interrupt_transfer(dev, 0x81, (unsigned char*)&status, sizeof(status), &sz, 100); + libusb_interrupt_transfer(dev, 0x81, (unsigned char*)&status, sizeof(status), &sz, 100); + //HACK!!!!! -> drop buffered data, read new one by reading twice. + ret = libusb_interrupt_transfer(dev, 0x81, (unsigned char*)&status, sizeof(status), &sz, 100); - for(i = 0; i<status.rxsz; i++) - { - libusb_bulk_transfer(dev, 0x85, (unsigned char*)&msg, sizeof(msg), &sz, 100); - n = write(canusb->wrpipe, &msg, sizeof(msg)); - } + for(i = 0; i<status.rxsz; i++) + { + libusb_bulk_transfer(dev, 0x85, (unsigned char*)&msg, sizeof(msg), &sz, 100); + n = write(canusb->wrpipe, &msg, sizeof(msg)); + } - } + } - libusb_close(dev); - libusb_exit(ctx); + libusb_close(dev); + libusb_exit(ctx); - return NULL; + return NULL; } static int canusb_startcapture(struct canusb_t* this) { - int pipefd[2]; + int pipefd[2]; - if (pipe(pipefd) == -1) return -1; + if (pipe(pipefd) == -1) + return -1; - canusb.rdpipe = pipefd[0]; - canusb.wrpipe = pipefd[1]; - canusb.loop = &loop; + canusb.rdpipe = pipefd[0]; + canusb.wrpipe = pipefd[1]; + canusb.loop = &loop; - loop = 1; - pthread_create(&this->worker, NULL, canusb_capture_thread, &canusb); + loop = 1; + pthread_create(&this->worker, NULL, canusb_capture_thread, &canusb); - return canusb.rdpipe; + return canusb.rdpipe; } static void canusb_clearbufs(struct canusb_t* this) { - unsigned char cmd[16]; - int al; + unsigned char cmd[16]; + int al; - cmd[0] = 1; //Empty incoming buffer - cmd[1] = 1; //Empty outgoing buffer - cmd[3] = 0; //Not a write to serial number - memset(&cmd[4],0,16-4); + cmd[0] = 1; //Empty incoming buffer + cmd[1] = 1; //Empty outgoing buffer + cmd[3] = 0; //Not a write to serial number + memset(&cmd[4],0,16-4); - libusb_interrupt_transfer(this->dev, 0x1,cmd,16,&al,100); + libusb_interrupt_transfer(this->dev, 0x1,cmd,16,&al,100); } static void canusb_close(pcap_t* handle) { - loop = 0; - pthread_join(canusb.worker, NULL); - - if (canusb.dev) - { - libusb_close(canusb.dev); - canusb.dev = NULL; - } + loop = 0; + pthread_join(canusb.worker, NULL); + + if (canusb.dev) + { + libusb_close(canusb.dev); + canusb.dev = NULL; + } } static int canusb_activate(pcap_t* handle) { - handle->read_op = canusb_read_linux; - - handle->inject_op = canusb_inject_linux; - handle->setfilter_op = canusb_setfilter_linux; - handle->setdirection_op = canusb_setdirection_linux; - handle->getnonblock_op = pcap_getnonblock_fd; - handle->setnonblock_op = pcap_setnonblock_fd; - handle->stats_op = canusb_stats_linux; - handle->cleanup_op = canusb_close; - - /* Initialize some components of the pcap structure. */ - handle->bufsize = 32; - handle->offset = 8; - handle->linktype = DLT_CAN_SOCKETCAN; - handle->set_datalink_op = NULL; - - char* serial = handle->opt.source + strlen("canusb"); - - canusb.dev = canusb_opendevice(canusb.ctx,serial); - if (!canusb.dev) - { - snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't open USB Device:"); - return PCAP_ERROR; - } - - canusb_clearbufs(&canusb); - - handle->fd = canusb_startcapture(&canusb); - handle->selectable_fd = handle->fd; - - return 0; + char *serial; + + handle->read_op = canusb_read_linux; + + handle->inject_op = canusb_inject_linux; + handle->setfilter_op = canusb_setfilter_linux; + handle->setdirection_op = canusb_setdirection_linux; + handle->getnonblock_op = pcap_getnonblock_fd; + handle->setnonblock_op = pcap_setnonblock_fd; + handle->stats_op = canusb_stats_linux; + handle->cleanup_op = canusb_close; + + /* Initialize some components of the pcap structure. */ + handle->bufsize = 32; + handle->offset = 8; + handle->linktype = DLT_CAN_SOCKETCAN; + handle->set_datalink_op = NULL; + + serial = handle->opt.source + strlen(CANUSB_IFACE); + canusb.serial = strdup(serial); + + canusb.dev = canusb_opendevice(canusb.ctx,serial); + if (!canusb.dev) + { + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't open USB Device:"); + return PCAP_ERROR; + } + + canusb_clearbufs(&canusb); + + handle->fd = canusb_startcapture(&canusb); + handle->selectable_fd = handle->fd; + + return 0; } @@ -345,83 +382,85 @@ static int canusb_activate(pcap_t* handle) static int canusb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) { - static struct timeval firstpacket = { -1, -1}; + static struct timeval firstpacket = { -1, -1}; - int msgsent = 0; - int i = 0; - struct CAN_Msg msg; - struct pcap_pkthdr pkth; + int msgsent = 0; + int i = 0; + struct CAN_Msg msg; + struct pcap_pkthdr pkth; - while(i < max_packets) - { - usleep(10 * 1000); - int n = read(handle->fd, &msg, sizeof(msg)); - if (n <= 0) break; - pkth.caplen = pkth.len = n; - pkth.caplen -= 4; - pkth.caplen -= 8 - msg.length; + while(i < max_packets) + { + int n; + usleep(10 * 1000); + n = read(handle->fd, &msg, sizeof(msg)); + if (n <= 0) + break; + pkth.caplen = pkth.len = n; + pkth.caplen -= 4; + pkth.caplen -= 8 - msg.length; - if ((firstpacket.tv_sec == -1) && (firstpacket.tv_usec == -1)) - gettimeofday(&firstpacket, NULL); + if ((firstpacket.tv_sec == -1) && (firstpacket.tv_usec == -1)) + gettimeofday(&firstpacket, NULL); - pkth.ts.tv_usec = firstpacket.tv_usec + (msg.timestamp % 100) * 10000; - pkth.ts.tv_sec = firstpacket.tv_usec + (msg.timestamp / 100); - if (pkth.ts.tv_usec > 1000000) - { - pkth.ts.tv_usec -= 1000000; - pkth.ts.tv_sec++; - } + pkth.ts.tv_usec = firstpacket.tv_usec + (msg.timestamp % 100) * 10000; + pkth.ts.tv_sec = firstpacket.tv_usec + (msg.timestamp / 100); + if (pkth.ts.tv_usec > 1000000) + { + pkth.ts.tv_usec -= 1000000; + pkth.ts.tv_sec++; + } - callback(user, &pkth, (void*)&msg.id); - i++; - } + callback(user, &pkth, (void*)&msg.id); + i++; + } - return i; + return i; } static int canusb_inject_linux(pcap_t *handle, const void *buf, size_t size) { - /* not yet implemented */ - snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on canusb devices"); - return (-1); + /* not yet implemented */ + snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on canusb devices"); + return (-1); } static int canusb_stats_linux(pcap_t *handle, struct pcap_stat *stats) { - /* not yet implemented */ - stats->ps_recv = 0; /* number of packets received */ - stats->ps_drop = 0; /* number of packets dropped */ - stats->ps_ifdrop = 0; /* drops by interface -- only supported on some platforms */ - return 0; + /* not yet implemented */ + stats->ps_recv = 0; /* number of packets received */ + stats->ps_drop = 0; /* number of packets dropped */ + stats->ps_ifdrop = 0; /* drops by interface -- only supported on some platforms */ + return 0; } static int canusb_setfilter_linux(pcap_t *p, struct bpf_program *fp) { - /* not yet implemented */ - return 0; + /* not yet implemented */ + return 0; } static int canusb_setdirection_linux(pcap_t *p, pcap_direction_t d) { - /* no support for PCAP_D_OUT */ - if (d == PCAP_D_OUT) - { - snprintf(p->errbuf, sizeof(p->errbuf), - "Setting direction to PCAP_D_OUT is not supported on this interface"); - return -1; - } + /* no support for PCAP_D_OUT */ + if (d == PCAP_D_OUT) + { + snprintf(p->errbuf, sizeof(p->errbuf), + "Setting direction to PCAP_D_OUT is not supported on this interface"); + return -1; + } - p->direction = d; + p->direction = d; - return 0; + return 0; } |