2 * Copyright (c) 2009 Felix Obenhuber
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior written
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * SocketCan sniffing API implementation for Linux platform
31 * By Felix Obenhuber <felix@obenhuber.de>
40 #include "pcap-can-linux.h"
42 #define CAN_CONTROL_SIZE 8
44 #ifdef NEED_STRERROR_H
53 #include <sys/ioctl.h>
54 #include <sys/socket.h>
56 #include <arpa/inet.h>
58 #include <linux/can.h>
59 #include <linux/can/raw.h>
61 /* not yet defined anywhere */
69 /* forward declaration */
70 static int can_activate(pcap_t
*);
71 static int can_read_linux(pcap_t
*, int , pcap_handler
, u_char
*);
72 static int can_inject_linux(pcap_t
*, const void *, size_t);
73 static int can_setfilter_linux(pcap_t
*, struct bpf_program
*);
74 static int can_setdirection_linux(pcap_t
*, pcap_direction_t
);
75 static int can_stats_linux(pcap_t
*, struct pcap_stat
*);
78 * Private data for capturing on Linux CANbus devices.
81 int ifindex
; /* interface index of device we're bound to */
85 can_findalldevs(pcap_if_t
**devlistp
, char *errbuf
)
88 * There are no platform-specific devices since each device
89 * exists as a regular network interface.
97 can_create(const char *device
, char *ebuf
, int *is_ours
)
104 /* Does this look like a CANbus device? */
105 cp
= strrchr(device
, '/');
108 /* Does it begin with "can" or "vcan"? */
109 if (strncmp(cp
, "can", 3) == 0) {
110 /* Begins with "can" */
111 cp
+= 3; /* skip past "can" */
112 } else if (strncmp(cp
, "vcan", 4) == 0) {
113 /* Begins with "vcan" */
116 /* Nope, doesn't begin with "can" or "vcan" */
120 /* Yes - is "can" or "vcan" followed by a number from 0? */
121 devnum
= strtol(cp
, &cpend
, 10);
122 if (cpend
== cp
|| *cpend
!= '\0') {
123 /* Not followed by a number. */
128 /* Followed by a non-valid number. */
133 /* OK, it's probably ours. */
136 p
= pcap_create_common(ebuf
, sizeof (struct pcap_can
));
140 p
->activate_op
= can_activate
;
146 can_activate(pcap_t
* handle
)
148 struct pcap_can
*handlep
= handle
->priv
;
149 struct sockaddr_can addr
;
152 /* Initialize some components of the pcap structure. */
153 handle
->bufsize
= CAN_CONTROL_SIZE
+ 16;
154 handle
->linktype
= DLT_CAN_SOCKETCAN_BIGENDIAN
;
155 handle
->read_op
= can_read_linux
;
156 handle
->inject_op
= can_inject_linux
;
157 handle
->setfilter_op
= can_setfilter_linux
;
158 handle
->setdirection_op
= can_setdirection_linux
;
159 handle
->set_datalink_op
= NULL
;
160 handle
->getnonblock_op
= pcap_getnonblock_fd
;
161 handle
->setnonblock_op
= pcap_setnonblock_fd
;
162 handle
->stats_op
= can_stats_linux
;
165 handle
->fd
= socket(PF_CAN
, SOCK_RAW
, CAN_RAW
);
168 pcap_snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't create raw socket %d:%s",
169 errno
, strerror(errno
));
173 /* get interface index */
174 memset(&ifr
, 0, sizeof(ifr
));
175 strlcpy(ifr
.ifr_name
, handle
->opt
.device
, sizeof(ifr
.ifr_name
));
176 if (ioctl(handle
->fd
, SIOCGIFINDEX
, &ifr
) < 0)
178 pcap_snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
179 "Unable to get interface index: %s",
180 pcap_strerror(errno
));
181 pcap_cleanup_live_common(handle
);
184 handlep
->ifindex
= ifr
.ifr_ifindex
;
186 /* allocate butter */
187 handle
->buffer
= malloc(handle
->bufsize
);
190 pcap_snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't allocate dump buffer: %s",
191 pcap_strerror(errno
));
192 pcap_cleanup_live_common(handle
);
196 /* Bind to the socket */
197 addr
.can_family
= AF_CAN
;
198 addr
.can_ifindex
= handlep
->ifindex
;
199 if( bind( handle
->fd
, (struct sockaddr
*)&addr
, sizeof(addr
) ) < 0 )
201 pcap_snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't attach to device %d %d:%s",
202 handlep
->ifindex
, errno
, strerror(errno
));
203 pcap_cleanup_live_common(handle
);
207 if (handle
->opt
.rfmon
)
209 /* Monitor mode doesn't apply to CAN devices. */
210 pcap_cleanup_live_common(handle
);
211 return PCAP_ERROR_RFMON_NOTSUP
;
214 handle
->selectable_fd
= handle
->fd
;
221 can_read_linux(pcap_t
*handle
, int max_packets
, pcap_handler callback
, u_char
*user
)
224 struct pcap_pkthdr pkth
;
227 struct can_frame
* cf
;
230 pktd
= (u_char
*)handle
->buffer
+ CAN_CONTROL_SIZE
;
232 iv
.iov_len
= handle
->snapshot
;
234 memset(&msg
, 0, sizeof(msg
));
237 msg
.msg_control
= handle
->buffer
;
238 msg
.msg_controllen
= CAN_CONTROL_SIZE
;
242 len
= recvmsg(handle
->fd
, &msg
, 0);
243 if (handle
->break_loop
)
245 handle
->break_loop
= 0;
248 } while ((len
== -1) && (errno
== EINTR
));
252 pcap_snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't receive packet %d:%s",
253 errno
, strerror(errno
));
256 pkth
.caplen
= (bpf_u_int32
)len
;
258 /* adjust capture len according to frame len */
259 cf
= (struct can_frame
*)(void *)pktd
;
260 pkth
.caplen
-= CAN_CONTROL_SIZE
- cf
->can_dlc
;
261 pkth
.len
= pkth
.caplen
;
263 cf
->can_id
= htonl( cf
->can_id
);
265 if( -1 == gettimeofday(&pkth
.ts
, NULL
) )
267 pcap_snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't get time of day %d:%s",
268 errno
, strerror(errno
));
272 callback(user
, &pkth
, pktd
);
279 can_inject_linux(pcap_t
*handle
, const void *buf
, size_t size
)
281 /* not yet implemented */
282 pcap_snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "inject not supported on "
289 can_stats_linux(pcap_t
*handle
, struct pcap_stat
*stats
)
291 /* not yet implemented */
292 stats
->ps_recv
= 0; /* number of packets received */
293 stats
->ps_drop
= 0; /* number of packets dropped */
294 stats
->ps_ifdrop
= 0; /* drops by interface -- only supported on some platforms */
300 can_setfilter_linux(pcap_t
*p
, struct bpf_program
*fp
)
302 /* not yet implemented */
308 can_setdirection_linux(pcap_t
*p
, pcap_direction_t d
)
310 /* no support for PCAP_D_OUT */
313 pcap_snprintf(p
->errbuf
, sizeof(p
->errbuf
),
314 "Setting direction to PCAP_D_OUT is not supported on can");