1 /* $NetBSD: pcap-can-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 * SocketCan sniffing API implementation for Linux platform
33 * By Felix Obenhuber <felix@obenhuber.de>
37 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: pcap-can-linux.c,v 1.3 2015/03/31 21:39:42 christos Exp $");
45 #include "pcap-can-linux.h"
47 #ifdef NEED_STRERROR_H
56 #include <sys/ioctl.h>
57 #include <sys/socket.h>
59 #include <arpa/inet.h>
61 #include <linux/can.h>
62 #include <linux/can/raw.h>
64 /* not yet defined anywhere */
72 /* forward declaration */
73 static int can_activate(pcap_t
*);
74 static int can_read_linux(pcap_t
*, int , pcap_handler
, u_char
*);
75 static int can_inject_linux(pcap_t
*, const void *, size_t);
76 static int can_setfilter_linux(pcap_t
*, struct bpf_program
*);
77 static int can_setdirection_linux(pcap_t
*, pcap_direction_t
);
78 static int can_stats_linux(pcap_t
*, struct pcap_stat
*);
81 * Private data for capturing on Linux CANbus devices.
84 int ifindex
; /* interface index of device we're bound to */
88 can_findalldevs(pcap_if_t
**devlistp
, char *errbuf
)
91 * There are no platform-specific devices since each device
92 * exists as a regular network interface.
100 can_create(const char *device
, char *ebuf
, int *is_ours
)
107 /* Does this look like a CANbus device? */
108 cp
= strrchr(device
, '/');
111 /* Does it begin with "can" or "vcan"? */
112 if (strncmp(cp
, "can", 3) == 0) {
113 /* Begins with "can" */
114 cp
+= 3; /* skip past "can" */
115 } else if (strncmp(cp
, "vcan", 4) == 0) {
116 /* Begins with "vcan" */
119 /* Nope, doesn't begin with "can" or "vcan" */
123 /* Yes - is "can" or "vcan" followed by a number from 0? */
124 devnum
= strtol(cp
, &cpend
, 10);
125 if (cpend
== cp
|| *cpend
!= '\0') {
126 /* Not followed by a number. */
131 /* Followed by a non-valid number. */
136 /* OK, it's probably ours. */
139 p
= pcap_create_common(device
, ebuf
, sizeof (struct pcap_can
));
143 p
->activate_op
= can_activate
;
149 can_activate(pcap_t
* handle
)
151 struct pcap_can
*handlep
= handle
->priv
;
152 struct sockaddr_can addr
;
155 /* Initialize some components of the pcap structure. */
156 handle
->bufsize
= 24;
158 handle
->linktype
= DLT_CAN_SOCKETCAN
;
159 handle
->read_op
= can_read_linux
;
160 handle
->inject_op
= can_inject_linux
;
161 handle
->setfilter_op
= can_setfilter_linux
;
162 handle
->setdirection_op
= can_setdirection_linux
;
163 handle
->set_datalink_op
= NULL
;
164 handle
->getnonblock_op
= pcap_getnonblock_fd
;
165 handle
->setnonblock_op
= pcap_setnonblock_fd
;
166 handle
->stats_op
= can_stats_linux
;
169 handle
->fd
= socket(PF_CAN
, SOCK_RAW
, CAN_RAW
);
172 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't create raw socket %d:%s",
173 errno
, strerror(errno
));
177 /* get interface index */
178 memset(&ifr
, 0, sizeof(ifr
));
179 strlcpy(ifr
.ifr_name
, handle
->opt
.source
, sizeof(ifr
.ifr_name
));
180 if (ioctl(handle
->fd
, SIOCGIFINDEX
, &ifr
) < 0)
182 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
183 "Unable to get interface index: %s",
184 pcap_strerror(errno
));
185 pcap_cleanup_live_common(handle
);
188 handlep
->ifindex
= ifr
.ifr_ifindex
;
190 /* allocate butter */
191 handle
->buffer
= malloc(handle
->bufsize
);
194 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't allocate dump buffer: %s",
195 pcap_strerror(errno
));
196 pcap_cleanup_live_common(handle
);
200 /* Bind to the socket */
201 addr
.can_family
= AF_CAN
;
202 addr
.can_ifindex
= handlep
->ifindex
;
203 if( bind( handle
->fd
, (struct sockaddr
*)&addr
, sizeof(addr
) ) < 0 )
205 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't attach to device %d %d:%s",
206 handlep
->ifindex
, errno
, strerror(errno
));
207 pcap_cleanup_live_common(handle
);
211 if (handle
->opt
.rfmon
)
213 /* Monitor mode doesn't apply to CAN devices. */
214 pcap_cleanup_live_common(handle
);
215 return PCAP_ERROR_RFMON_NOTSUP
;
218 handle
->selectable_fd
= handle
->fd
;
225 can_read_linux(pcap_t
*handle
, int max_packets
, pcap_handler callback
, u_char
*user
)
228 struct pcap_pkthdr pkth
;
230 struct can_frame
* cf
;
232 iv
.iov_base
= &handle
->buffer
[handle
->offset
];
233 iv
.iov_len
= handle
->snapshot
;
235 memset(&msg
, 0, sizeof(msg
));
238 msg
.msg_control
= handle
->buffer
;
239 msg
.msg_controllen
= handle
->offset
;
243 pkth
.caplen
= recvmsg(handle
->fd
, &msg
, 0);
244 if (handle
->break_loop
)
246 handle
->break_loop
= 0;
249 } while ((pkth
.caplen
== -1) && (errno
== EINTR
));
251 if (pkth
.caplen
== -1)
253 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't receive packet %d:%s",
254 errno
, strerror(errno
));
258 /* adjust capture len according to frame len */
259 cf
= (struct can_frame
*)&handle
->buffer
[8];
260 pkth
.caplen
-= 8 - cf
->can_dlc
;
261 pkth
.len
= pkth
.caplen
;
263 cf
->can_id
= htonl( cf
->can_id
);
265 if( -1 == gettimeofday(&pkth
.ts
, NULL
) )
267 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "Can't get time of day %d:%s",
268 errno
, strerror(errno
));
272 callback(user
, &pkth
, &handle
->buffer
[8]);
279 can_inject_linux(pcap_t
*handle
, const void *buf
, size_t size
)
281 /* not yet implemented */
282 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 snprintf(p
->errbuf
, sizeof(p
->errbuf
),
314 "Setting direction to PCAP_D_OUT is not supported on can");