1 /* $NetBSD: pcap-can-linux.c,v 1.3 2015/03/31 21:39:42 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Felix Obenhuber 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 18 * permission. 19 * 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. 31 * 32 * SocketCan sniffing API implementation for Linux platform 33 * By Felix Obenhuber <felix@obenhuber.de> 34 * 35 */ 36 37 #include <sys/cdefs.h> 38 __RCSID("$NetBSD: pcap-can-linux.c,v 1.3 2015/03/31 21:39:42 christos Exp $"); 39 40 #ifdef HAVE_CONFIG_H 41 #include "config.h" 42 #endif 43 44 #include "pcap-int.h" 45 #include "pcap-can-linux.h" 46 47 #ifdef NEED_STRERROR_H 48 #include "strerror.h" 49 #endif 50 51 #include <errno.h> 52 #include <stdlib.h> 53 #include <unistd.h> 54 #include <fcntl.h> 55 #include <string.h> 56 #include <sys/ioctl.h> 57 #include <sys/socket.h> 58 #include <net/if.h> 59 #include <arpa/inet.h> 60 61 #include <linux/can.h> 62 #include <linux/can/raw.h> 63 64 /* not yet defined anywhere */ 65 #ifndef PF_CAN 66 #define PF_CAN 29 67 #endif 68 #ifndef AF_CAN 69 #define AF_CAN PF_CAN 70 #endif 71 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 *); 79 80 /* 81 * Private data for capturing on Linux CANbus devices. 82 */ 83 struct pcap_can { 84 int ifindex; /* interface index of device we're bound to */ 85 }; 86 87 int 88 can_findalldevs(pcap_if_t **devlistp, char *errbuf) 89 { 90 /* 91 * There are no platform-specific devices since each device 92 * exists as a regular network interface. 93 * 94 * XXX - true? 95 */ 96 return 0; 97 } 98 99 pcap_t * 100 can_create(const char *device, char *ebuf, int *is_ours) 101 { 102 const char *cp; 103 char *cpend; 104 long devnum; 105 pcap_t* p; 106 107 /* Does this look like a CANbus device? */ 108 cp = strrchr(device, '/'); 109 if (cp == NULL) 110 cp = 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" */ 117 cp += 4; 118 } else { 119 /* Nope, doesn't begin with "can" or "vcan" */ 120 *is_ours = 0; 121 return NULL; 122 } 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. */ 127 *is_ours = 0; 128 return NULL; 129 } 130 if (devnum < 0) { 131 /* Followed by a non-valid number. */ 132 *is_ours = 0; 133 return NULL; 134 } 135 136 /* OK, it's probably ours. */ 137 *is_ours = 1; 138 139 p = pcap_create_common(device, ebuf, sizeof (struct pcap_can)); 140 if (p == NULL) 141 return (NULL); 142 143 p->activate_op = can_activate; 144 return (p); 145 } 146 147 148 static int 149 can_activate(pcap_t* handle) 150 { 151 struct pcap_can *handlep = handle->priv; 152 struct sockaddr_can addr; 153 struct ifreq ifr; 154 155 /* Initialize some components of the pcap structure. */ 156 handle->bufsize = 24; 157 handle->offset = 8; 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; 167 168 /* Create socket */ 169 handle->fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); 170 if (handle->fd < 0) 171 { 172 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", 173 errno, strerror(errno)); 174 return PCAP_ERROR; 175 } 176 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) 181 { 182 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 183 "Unable to get interface index: %s", 184 pcap_strerror(errno)); 185 pcap_cleanup_live_common(handle); 186 return PCAP_ERROR; 187 } 188 handlep->ifindex = ifr.ifr_ifindex; 189 190 /* allocate butter */ 191 handle->buffer = malloc(handle->bufsize); 192 if (!handle->buffer) 193 { 194 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", 195 pcap_strerror(errno)); 196 pcap_cleanup_live_common(handle); 197 return PCAP_ERROR; 198 } 199 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 ) 204 { 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); 208 return PCAP_ERROR; 209 } 210 211 if (handle->opt.rfmon) 212 { 213 /* Monitor mode doesn't apply to CAN devices. */ 214 pcap_cleanup_live_common(handle); 215 return PCAP_ERROR_RFMON_NOTSUP; 216 } 217 218 handle->selectable_fd = handle->fd; 219 return 0; 220 221 } 222 223 224 static int 225 can_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 226 { 227 struct msghdr msg; 228 struct pcap_pkthdr pkth; 229 struct iovec iv; 230 struct can_frame* cf; 231 232 iv.iov_base = &handle->buffer[handle->offset]; 233 iv.iov_len = handle->snapshot; 234 235 memset(&msg, 0, sizeof(msg)); 236 msg.msg_iov = &iv; 237 msg.msg_iovlen = 1; 238 msg.msg_control = handle->buffer; 239 msg.msg_controllen = handle->offset; 240 241 do 242 { 243 pkth.caplen = recvmsg(handle->fd, &msg, 0); 244 if (handle->break_loop) 245 { 246 handle->break_loop = 0; 247 return -2; 248 } 249 } while ((pkth.caplen == -1) && (errno == EINTR)); 250 251 if (pkth.caplen == -1) 252 { 253 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", 254 errno, strerror(errno)); 255 return -1; 256 } 257 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; 262 263 cf->can_id = htonl( cf->can_id ); 264 265 if( -1 == gettimeofday(&pkth.ts, NULL) ) 266 { 267 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get time of day %d:%s", 268 errno, strerror(errno)); 269 return -1; 270 } 271 272 callback(user, &pkth, &handle->buffer[8]); 273 274 return 1; 275 } 276 277 278 static int 279 can_inject_linux(pcap_t *handle, const void *buf, size_t size) 280 { 281 /* not yet implemented */ 282 snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " 283 "can devices"); 284 return (-1); 285 } 286 287 288 static int 289 can_stats_linux(pcap_t *handle, struct pcap_stat *stats) 290 { 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 */ 295 return 0; 296 } 297 298 299 static int 300 can_setfilter_linux(pcap_t *p, struct bpf_program *fp) 301 { 302 /* not yet implemented */ 303 return 0; 304 } 305 306 307 static int 308 can_setdirection_linux(pcap_t *p, pcap_direction_t d) 309 { 310 /* no support for PCAP_D_OUT */ 311 if (d == PCAP_D_OUT) 312 { 313 snprintf(p->errbuf, sizeof(p->errbuf), 314 "Setting direction to PCAP_D_OUT is not supported on can"); 315 return -1; 316 } 317 318 p->direction = d; 319 320 return 0; 321 } 322 323 324 /* eof */ 325