1 /* $NetBSD: pcap-canusb-linux.c,v 1.3 2015/03/31 21:39:42 christos Exp $ */
4 * Copyright (c) 2009 Felix Obenhuber
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior written
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * Sockettrace sniffing API implementation for Linux platform
33 * By Felix Obenhuber <felix@obenhuber.de>
37 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: pcap-canusb-linux.c,v 1.3 2015/03/31 21:39:42 christos Exp $");
44 #include <libusb-1.0/libusb.h>
54 #include "pcap-canusb-linux.h"
56 #define CANUSB_IFACE "canusb"
58 #define CANUSB_VID 0x0403
59 #define CANUSB_PID 0x8990
68 /* forward declaration */
69 static int canusb_activate(pcap_t
*);
70 static int canusb_read_linux(pcap_t
*, int , pcap_handler
, u_char
*);
71 static int canusb_inject_linux(pcap_t
*, const void *, size_t);
72 static int canusb_setfilter_linux(pcap_t
*, struct bpf_program
*);
73 static int canusb_setdirection_linux(pcap_t
*, pcap_direction_t
);
74 static int canusb_stats_linux(pcap_t
*, struct pcap_stat
*);
85 * Private data for capturing on Linux CANbus USB devices.
89 libusb_device_handle
*dev
;
95 int canusb_findalldevs(pcap_if_t
**alldevsp
, char *err_str
)
97 libusb_context
*fdctx
;
99 unsigned char sernum
[65];
102 if (libusb_init(&fdctx
) != 0) {
104 * XXX - if this doesn't just mean "no USB file system mounted",
105 * perhaps we should report a real error rather than just
106 * saying "no CANUSB devices".
111 cnt
= libusb_get_device_list(fdctx
,&devs
);
116 // Check if this device is interesting.
117 struct libusb_device_descriptor desc
;
118 libusb_get_device_descriptor(devs
[i
],&desc
);
120 if ((desc
.idVendor
!= CANUSB_VID
) || (desc
.idProduct
!= CANUSB_PID
))
121 continue; //It is not, check next device
124 libusb_device_handle
*dh
= NULL
;
126 if ((ret
= libusb_open(devs
[i
],&dh
)) == 0)
130 int n
= libusb_get_string_descriptor_ascii(dh
,desc
.iSerialNumber
,sernum
,64);
133 snprintf(dev_name
, 30, CANUSB_IFACE
"%s", sernum
);
134 snprintf(dev_descr
, 50, "CanUSB [%s]", sernum
);
138 if (pcap_add_if(alldevsp
, dev_name
, 0, dev_descr
, err_str
) < 0)
140 libusb_free_device_list(devs
,1);
147 libusb_free_device_list(devs
,1);
152 static libusb_device_handle
* canusb_opendevice(struct libusb_context
*ctx
, char* devserial
)
154 libusb_device
** devs
;
155 unsigned char serial
[65];
158 cnt
= libusb_get_device_list(ctx
,&devs
);
162 // Check if this device is interesting.
163 struct libusb_device_descriptor desc
;
164 libusb_get_device_descriptor(devs
[i
],&desc
);
166 if ((desc
.idVendor
!= CANUSB_VID
) || (desc
.idProduct
!= CANUSB_PID
))
170 libusb_device_handle
*dh
= NULL
;
172 if (libusb_open(devs
[i
],&dh
) != 0) continue;
174 n
= libusb_get_string_descriptor_ascii(dh
,desc
.iSerialNumber
,serial
,64);
177 if ((devserial
) && (strcmp((char *)serial
,devserial
) != 0))
183 if ((libusb_kernel_driver_active(dh
,0)) && (libusb_detach_kernel_driver(dh
,0) != 0))
189 if (libusb_set_configuration(dh
,1) != 0)
195 if (libusb_claim_interface(dh
,0) != 0)
202 libusb_free_device_list(devs
,1);
206 libusb_free_device_list(devs
,1);
212 canusb_create(const char *device
, char *ebuf
, int *is_ours
)
218 struct pcap_canusb
*canusb
;
220 /* Does this look like a DAG device? */
221 cp
= strrchr(device
, '/');
224 /* Does it begin with "canusb"? */
225 if (strncmp(cp
, "canusb", 6) != 0) {
226 /* Nope, doesn't begin with "canusb" */
230 /* Yes - is "canusb" followed by a number? */
232 devnum
= strtol(cp
, &cpend
, 10);
233 if (cpend
== cp
|| *cpend
!= '\0') {
234 /* Not followed by a number. */
239 /* Followed by a non-valid number. */
244 /* OK, it's probably ours. */
247 p
= pcap_create_common(device
, ebuf
, sizeof (struct pcap_canusb
));
257 p
->activate_op
= canusb_activate
;
263 static void* canusb_capture_thread(void *arg
)
265 struct pcap_canusb
*canusb
= arg
;
272 fcntl(canusb
->wrpipe
, F_SETFL
, O_NONBLOCK
);
279 libusb_interrupt_transfer(canusb
->dev
, 0x81, (unsigned char*)&status
, sizeof(status
), &sz
, 100);
280 //HACK!!!!! -> drop buffered data, read new one by reading twice.
281 libusb_interrupt_transfer(canusb
->dev
, 0x81, (unsigned char*)&status
, sizeof(status
), &sz
, 100);
283 for(i
= 0; i
<status
.rxsz
; i
++)
285 libusb_bulk_transfer(canusb
->dev
, 0x85, (unsigned char*)&msg
, sizeof(msg
), &sz
, 100);
286 if(write(canusb
->wrpipe
, &msg
, sizeof(msg
)) < 0)
287 fprintf(stderr
,"write() error: %s\n", strerror(errno
));
295 static int canusb_startcapture(struct pcap_canusb
* this)
299 if (pipe(pipefd
) == -1)
302 this->rdpipe
= pipefd
[0];
303 this->wrpipe
= pipefd
[1];
306 pthread_create(&this->worker
, NULL
, canusb_capture_thread
, this);
311 static void canusb_clearbufs(struct pcap_canusb
* this)
313 unsigned char cmd
[16];
316 cmd
[0] = 1; //Empty incoming buffer
317 cmd
[1] = 1; //Empty outgoing buffer
318 cmd
[3] = 0; //Not a write to serial number
319 memset(&cmd
[4],0,16-4);
321 libusb_interrupt_transfer(this->dev
, 0x1,cmd
,16,&al
,100);
325 static void canusb_close(pcap_t
* handle
)
327 struct pcap_canusb
*canusb
= handle
->priv
;
330 pthread_join(canusb
->worker
, NULL
);
334 libusb_close(canusb
->dev
);
339 libusb_exit(canusb
->ctx
);
346 static int canusb_activate(pcap_t
* handle
)
348 struct pcap_canusb
*canusb
= handle
->priv
;
351 if (libusb_init(&canusb
->ctx
) != 0) {
353 * XXX - what causes this to fail?
355 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "libusb_init() failed");
359 handle
->read_op
= canusb_read_linux
;
361 handle
->inject_op
= canusb_inject_linux
;
362 handle
->setfilter_op
= canusb_setfilter_linux
;
363 handle
->setdirection_op
= canusb_setdirection_linux
;
364 handle
->getnonblock_op
= pcap_getnonblock_fd
;
365 handle
->setnonblock_op
= pcap_setnonblock_fd
;
366 handle
->stats_op
= canusb_stats_linux
;
367 handle
->cleanup_op
= canusb_close
;
369 /* Initialize some components of the pcap structure. */
370 handle
->bufsize
= 32;
372 handle
->linktype
= DLT_CAN_SOCKETCAN
;
373 handle
->set_datalink_op
= NULL
;
375 serial
= handle
->opt
.source
+ strlen(CANUSB_IFACE
);
377 canusb
->dev
= canusb_opendevice(canusb
->ctx
, serial
);
380 libusb_exit(canusb
->ctx
);
381 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't open USB Device");
385 canusb_clearbufs(canusb
);
387 handle
->fd
= canusb_startcapture(canusb
);
388 handle
->selectable_fd
= handle
->fd
;
397 canusb_read_linux(pcap_t
*handle
, int max_packets
, pcap_handler callback
, u_char
*user
)
399 static struct timeval firstpacket
= { -1, -1};
402 struct pcap_pkthdr pkth
;
404 while(i
< max_packets
)
408 n
= read(handle
->fd
, &msg
, sizeof(msg
));
411 pkth
.caplen
= pkth
.len
= n
;
413 pkth
.caplen
-= 8 - msg
.length
;
415 if ((firstpacket
.tv_sec
== -1) && (firstpacket
.tv_usec
== -1))
416 gettimeofday(&firstpacket
, NULL
);
418 pkth
.ts
.tv_usec
= firstpacket
.tv_usec
+ (msg
.timestamp
% 100) * 10000;
419 pkth
.ts
.tv_sec
= firstpacket
.tv_usec
+ (msg
.timestamp
/ 100);
420 if (pkth
.ts
.tv_usec
> 1000000)
422 pkth
.ts
.tv_usec
-= 1000000;
426 callback(user
, &pkth
, (void*)&msg
.id
);
435 canusb_inject_linux(pcap_t
*handle
, const void *buf
, size_t size
)
437 /* not yet implemented */
438 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "inject not supported on canusb devices");
444 canusb_stats_linux(pcap_t
*handle
, struct pcap_stat
*stats
)
446 /* not yet implemented */
447 stats
->ps_recv
= 0; /* number of packets received */
448 stats
->ps_drop
= 0; /* number of packets dropped */
449 stats
->ps_ifdrop
= 0; /* drops by interface -- only supported on some platforms */
455 canusb_setfilter_linux(pcap_t
*p
, struct bpf_program
*fp
)
457 /* not yet implemented */
463 canusb_setdirection_linux(pcap_t
*p
, pcap_direction_t d
)
465 /* no support for PCAP_D_OUT */
468 snprintf(p
->errbuf
, sizeof(p
->errbuf
),
469 "Setting direction to PCAP_D_OUT is not supported on this interface");