1214455Srpaulo/* 2214455Srpaulo * Copyright (c) 2009 Felix Obenhuber 3214455Srpaulo * All rights reserved. 4214455Srpaulo * 5214455Srpaulo * Redistribution and use in source and binary forms, with or without 6214455Srpaulo * modification, are permitted provided that the following conditions 7214455Srpaulo * are met: 8214455Srpaulo * 9214455Srpaulo * 1. Redistributions of source code must retain the above copyright 10214455Srpaulo * notice, this list of conditions and the following disclaimer. 11214455Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 12214455Srpaulo * notice, this list of conditions and the following disclaimer in the 13214455Srpaulo * documentation and/or other materials provided with the distribution. 14214455Srpaulo * 3. The name of the author may not be used to endorse or promote 15214455Srpaulo * products derived from this software without specific prior written 16214455Srpaulo * permission. 17214455Srpaulo * 18214455Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19214455Srpaulo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20214455Srpaulo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21214455Srpaulo * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22214455Srpaulo * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23214455Srpaulo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24214455Srpaulo * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25214455Srpaulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26214455Srpaulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27214455Srpaulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28214455Srpaulo * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29214455Srpaulo * 30214455Srpaulo * SocketCan sniffing API implementation for Linux platform 31214455Srpaulo * By Felix Obenhuber <felix@obenhuber.de> 32214455Srpaulo * 33214455Srpaulo */ 34214455Srpaulo 35214455Srpaulo#ifdef HAVE_CONFIG_H 36214455Srpaulo#include "config.h" 37214455Srpaulo#endif 38214455Srpaulo 39214455Srpaulo#include "pcap-int.h" 40214455Srpaulo#include "pcap-can-linux.h" 41214455Srpaulo 42214455Srpaulo#ifdef NEED_STRERROR_H 43214455Srpaulo#include "strerror.h" 44214455Srpaulo#endif 45214455Srpaulo 46214455Srpaulo#include <errno.h> 47214455Srpaulo#include <stdlib.h> 48214455Srpaulo#include <unistd.h> 49214455Srpaulo#include <fcntl.h> 50214455Srpaulo#include <string.h> 51214455Srpaulo#include <sys/ioctl.h> 52214455Srpaulo#include <sys/socket.h> 53214455Srpaulo#include <net/if.h> 54214455Srpaulo#include <arpa/inet.h> 55214455Srpaulo 56214455Srpaulo#include <linux/can.h> 57214455Srpaulo#include <linux/can/raw.h> 58214455Srpaulo 59214455Srpaulo/* not yet defined anywhere */ 60214455Srpaulo#ifndef PF_CAN 61214455Srpaulo#define PF_CAN 29 62214455Srpaulo#endif 63214455Srpaulo#ifndef AF_CAN 64214455Srpaulo#define AF_CAN PF_CAN 65214455Srpaulo#endif 66214455Srpaulo 67214455Srpaulo/* forward declaration */ 68214455Srpaulostatic int can_activate(pcap_t *); 69214455Srpaulostatic int can_read_linux(pcap_t *, int , pcap_handler , u_char *); 70214455Srpaulostatic int can_inject_linux(pcap_t *, const void *, size_t); 71214455Srpaulostatic int can_setfilter_linux(pcap_t *, struct bpf_program *); 72214455Srpaulostatic int can_setdirection_linux(pcap_t *, pcap_direction_t); 73214455Srpaulostatic int can_stats_linux(pcap_t *, struct pcap_stat *); 74214455Srpaulo 75252281Sdelphijint 76252281Sdelphijcan_findalldevs(pcap_if_t **devlistp, char *errbuf) 77252281Sdelphij{ 78252281Sdelphij /* 79252281Sdelphij * There are no platform-specific devices since each device 80252281Sdelphij * exists as a regular network interface. 81252281Sdelphij * 82252281Sdelphij * XXX - true? 83252281Sdelphij */ 84252281Sdelphij return 0; 85252281Sdelphij} 86252281Sdelphij 87214455Srpaulopcap_t * 88252281Sdelphijcan_create(const char *device, char *ebuf, int *is_ours) 89214455Srpaulo{ 90252281Sdelphij const char *cp; 91252281Sdelphij char *cpend; 92252281Sdelphij long devnum; 93214455Srpaulo pcap_t* p; 94214455Srpaulo 95252281Sdelphij /* Does this look like a CANbus device? */ 96252281Sdelphij cp = strrchr(device, '/'); 97252281Sdelphij if (cp == NULL) 98252281Sdelphij cp = device; 99252281Sdelphij /* Does it begin with "can" or "vcan"? */ 100252281Sdelphij if (strncmp(cp, "can", 3) == 0) { 101252281Sdelphij /* Begins with "can" */ 102252281Sdelphij cp += 3; /* skip past "can" */ 103252281Sdelphij } else if (strncmp(cp, "vcan", 4) == 0) { 104252281Sdelphij /* Begins with "vcan" */ 105252281Sdelphij cp += 4; 106252281Sdelphij } else { 107252281Sdelphij /* Nope, doesn't begin with "can" or "vcan" */ 108252281Sdelphij *is_ours = 0; 109252281Sdelphij return NULL; 110252281Sdelphij } 111252281Sdelphij /* Yes - is "can" or "vcan" followed by a number from 0? */ 112252281Sdelphij devnum = strtol(cp, &cpend, 10); 113252281Sdelphij if (cpend == cp || *cpend != '\0') { 114252281Sdelphij /* Not followed by a number. */ 115252281Sdelphij *is_ours = 0; 116252281Sdelphij return NULL; 117252281Sdelphij } 118252281Sdelphij if (devnum < 0) { 119252281Sdelphij /* Followed by a non-valid number. */ 120252281Sdelphij *is_ours = 0; 121252281Sdelphij return NULL; 122252281Sdelphij } 123252281Sdelphij 124252281Sdelphij /* OK, it's probably ours. */ 125252281Sdelphij *is_ours = 1; 126252281Sdelphij 127214455Srpaulo p = pcap_create_common(device, ebuf); 128214455Srpaulo if (p == NULL) 129214455Srpaulo return (NULL); 130214455Srpaulo 131214455Srpaulo p->activate_op = can_activate; 132214455Srpaulo return (p); 133214455Srpaulo} 134214455Srpaulo 135214455Srpaulo 136214455Srpaulostatic int 137214455Srpaulocan_activate(pcap_t* handle) 138214455Srpaulo{ 139214455Srpaulo struct sockaddr_can addr; 140214455Srpaulo struct ifreq ifr; 141214455Srpaulo 142214455Srpaulo /* Initialize some components of the pcap structure. */ 143214455Srpaulo handle->bufsize = 24; 144214455Srpaulo handle->offset = 8; 145214455Srpaulo handle->linktype = DLT_CAN_SOCKETCAN; 146214455Srpaulo handle->read_op = can_read_linux; 147214455Srpaulo handle->inject_op = can_inject_linux; 148214455Srpaulo handle->setfilter_op = can_setfilter_linux; 149214455Srpaulo handle->setdirection_op = can_setdirection_linux; 150214455Srpaulo handle->set_datalink_op = NULL; 151214455Srpaulo handle->getnonblock_op = pcap_getnonblock_fd; 152214455Srpaulo handle->setnonblock_op = pcap_setnonblock_fd; 153214455Srpaulo handle->stats_op = can_stats_linux; 154214455Srpaulo 155214455Srpaulo /* Create socket */ 156214455Srpaulo handle->fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); 157214455Srpaulo if (handle->fd < 0) 158214455Srpaulo { 159214455Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", 160214455Srpaulo errno, strerror(errno)); 161214455Srpaulo return PCAP_ERROR; 162214455Srpaulo } 163214455Srpaulo 164214455Srpaulo /* get interface index */ 165214455Srpaulo memset(&ifr, 0, sizeof(ifr)); 166214455Srpaulo strncpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name)); 167214455Srpaulo if (ioctl(handle->fd, SIOCGIFINDEX, &ifr) < 0) 168214455Srpaulo { 169214455Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, 170214455Srpaulo "Unable to get interface index: %s", 171214455Srpaulo pcap_strerror(errno)); 172214455Srpaulo pcap_cleanup_live_common(handle); 173214455Srpaulo return PCAP_ERROR; 174214455Srpaulo } 175214455Srpaulo handle->md.ifindex = ifr.ifr_ifindex; 176214455Srpaulo 177214455Srpaulo /* allocate butter */ 178214455Srpaulo handle->buffer = malloc(handle->bufsize); 179214455Srpaulo if (!handle->buffer) 180214455Srpaulo { 181214455Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", 182214455Srpaulo pcap_strerror(errno)); 183214455Srpaulo pcap_cleanup_live_common(handle); 184214455Srpaulo return PCAP_ERROR; 185214455Srpaulo } 186214455Srpaulo 187214455Srpaulo /* Bind to the socket */ 188214455Srpaulo addr.can_family = AF_CAN; 189214455Srpaulo addr.can_ifindex = handle->md.ifindex; 190214455Srpaulo if( bind( handle->fd, (struct sockaddr*)&addr, sizeof(addr) ) < 0 ) 191214455Srpaulo { 192214455Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't attach to device %d %d:%s", 193214455Srpaulo handle->md.ifindex, errno, strerror(errno)); 194214455Srpaulo pcap_cleanup_live_common(handle); 195214455Srpaulo return PCAP_ERROR; 196214455Srpaulo } 197214455Srpaulo 198214455Srpaulo if (handle->opt.rfmon) 199214455Srpaulo { 200214455Srpaulo /* Monitor mode doesn't apply to CAN devices. */ 201214455Srpaulo pcap_cleanup_live_common(handle); 202214455Srpaulo return PCAP_ERROR; 203214455Srpaulo } 204214455Srpaulo 205214455Srpaulo handle->selectable_fd = handle->fd; 206214455Srpaulo return 0; 207214455Srpaulo 208214455Srpaulo} 209214455Srpaulo 210214455Srpaulo 211214455Srpaulostatic int 212214455Srpaulocan_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) 213214455Srpaulo{ 214214455Srpaulo struct msghdr msg; 215214455Srpaulo struct pcap_pkthdr pkth; 216214455Srpaulo struct iovec iv; 217214455Srpaulo struct can_frame* cf; 218214455Srpaulo 219214455Srpaulo iv.iov_base = &handle->buffer[handle->offset]; 220214455Srpaulo iv.iov_len = handle->snapshot; 221214455Srpaulo 222214455Srpaulo memset(&msg, 0, sizeof(msg)); 223214455Srpaulo msg.msg_iov = &iv; 224214455Srpaulo msg.msg_iovlen = 1; 225214455Srpaulo msg.msg_control = handle->buffer; 226214455Srpaulo msg.msg_controllen = handle->offset; 227214455Srpaulo 228214455Srpaulo do 229214455Srpaulo { 230214455Srpaulo pkth.caplen = recvmsg(handle->fd, &msg, 0); 231214455Srpaulo if (handle->break_loop) 232214455Srpaulo { 233214455Srpaulo handle->break_loop = 0; 234214455Srpaulo return -2; 235214455Srpaulo } 236214455Srpaulo } while ((pkth.caplen == -1) && (errno == EINTR)); 237214455Srpaulo 238214455Srpaulo if (pkth.caplen < 0) 239214455Srpaulo { 240214455Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", 241214455Srpaulo errno, strerror(errno)); 242214455Srpaulo return -1; 243214455Srpaulo } 244214455Srpaulo 245214455Srpaulo /* adjust capture len according to frame len */ 246214455Srpaulo cf = (struct can_frame*)&handle->buffer[8]; 247214455Srpaulo pkth.caplen -= 8 - cf->can_dlc; 248214455Srpaulo pkth.len = pkth.caplen; 249214455Srpaulo 250214455Srpaulo cf->can_id = htonl( cf->can_id ); 251214455Srpaulo 252214455Srpaulo if( -1 == gettimeofday(&pkth.ts, NULL) ) 253214455Srpaulo { 254214455Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get time of day %d:%s", 255214455Srpaulo errno, strerror(errno)); 256214455Srpaulo return -1; 257214455Srpaulo } 258214455Srpaulo 259214455Srpaulo callback(user, &pkth, &handle->buffer[8]); 260214455Srpaulo 261214455Srpaulo return 1; 262214455Srpaulo} 263214455Srpaulo 264214455Srpaulo 265214455Srpaulostatic int 266214455Srpaulocan_inject_linux(pcap_t *handle, const void *buf, size_t size) 267214455Srpaulo{ 268214455Srpaulo /* not yet implemented */ 269214455Srpaulo snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on " 270214455Srpaulo "can devices"); 271214455Srpaulo return (-1); 272214455Srpaulo} 273214455Srpaulo 274214455Srpaulo 275214455Srpaulostatic int 276214455Srpaulocan_stats_linux(pcap_t *handle, struct pcap_stat *stats) 277214455Srpaulo{ 278214455Srpaulo /* not yet implemented */ 279214455Srpaulo stats->ps_recv = 0; /* number of packets received */ 280214455Srpaulo stats->ps_drop = 0; /* number of packets dropped */ 281214455Srpaulo stats->ps_ifdrop = 0; /* drops by interface -- only supported on some platforms */ 282214455Srpaulo return 0; 283214455Srpaulo} 284214455Srpaulo 285214455Srpaulo 286214455Srpaulostatic int 287214455Srpaulocan_setfilter_linux(pcap_t *p, struct bpf_program *fp) 288214455Srpaulo{ 289214455Srpaulo /* not yet implemented */ 290214455Srpaulo return 0; 291214455Srpaulo} 292214455Srpaulo 293214455Srpaulo 294214455Srpaulostatic int 295214455Srpaulocan_setdirection_linux(pcap_t *p, pcap_direction_t d) 296214455Srpaulo{ 297214455Srpaulo /* no support for PCAP_D_OUT */ 298214455Srpaulo if (d == PCAP_D_OUT) 299214455Srpaulo { 300214455Srpaulo snprintf(p->errbuf, sizeof(p->errbuf), 301214455Srpaulo "Setting direction to PCAP_D_OUT is not supported on can"); 302214455Srpaulo return -1; 303214455Srpaulo } 304214455Srpaulo 305214455Srpaulo p->direction = d; 306214455Srpaulo 307214455Srpaulo return 0; 308214455Srpaulo} 309214455Srpaulo 310214455Srpaulo 311214455Srpaulo/* eof */ 312