]> The Tcpdump Group git mirrors - libpcap/blobdiff - pcap-can-linux.c
Have routines to set various internal debugging flags.
[libpcap] / pcap-can-linux.c
index fb8e232c8973677d8a057713e596e7b3a3a5a885..b4e2a0083541566592968bd9384ba9c805904d87 100644 (file)
@@ -39,6 +39,8 @@
 #include "pcap-int.h"
 #include "pcap-can-linux.h"
 
+#define CAN_CONTROL_SIZE 8
+
 #ifdef NEED_STRERROR_H
 #include "strerror.h"
 #endif
@@ -72,12 +74,66 @@ static int can_setfilter_linux(pcap_t *, struct bpf_program *);
 static int can_setdirection_linux(pcap_t *, pcap_direction_t);
 static int can_stats_linux(pcap_t *, struct pcap_stat *);
 
+/*
+ * Private data for capturing on Linux CANbus devices.
+ */
+struct pcap_can {
+       int ifindex;            /* interface index of device we're bound to */
+};
+
+int
+can_findalldevs(pcap_if_t **devlistp, char *errbuf)
+{
+       /*
+        * There are no platform-specific devices since each device
+        * exists as a regular network interface.
+        *
+        * XXX - true?
+        */
+       return 0;
+}
+
 pcap_t *
-can_create(const char *device, char *ebuf)
+can_create(const char *device, char *ebuf, int *is_ours)
 {
+       const char *cp;
+       char *cpend;
+       long devnum;
        pcap_t* p;
 
-       p = pcap_create_common(device, ebuf);
+       /* Does this look like a CANbus device? */
+       cp = strrchr(device, '/');
+       if (cp == NULL)
+               cp = device;
+       /* Does it begin with "can" or "vcan"? */
+       if (strncmp(cp, "can", 3) == 0) {
+               /* Begins with "can" */
+               cp += 3;        /* skip past "can" */
+       } else if (strncmp(cp, "vcan", 4) == 0) {
+               /* Begins with "vcan" */
+               cp += 4;
+       } else {
+               /* Nope, doesn't begin with "can" or "vcan" */
+               *is_ours = 0;
+               return NULL;
+       }
+       /* Yes - is "can" or "vcan" followed by a number from 0? */
+       devnum = strtol(cp, &cpend, 10);
+       if (cpend == cp || *cpend != '\0') {
+               /* Not followed by a number. */
+               *is_ours = 0;
+               return NULL;
+       }
+       if (devnum < 0) {
+               /* Followed by a non-valid number. */
+               *is_ours = 0;
+               return NULL;
+       }
+
+       /* OK, it's probably ours. */
+       *is_ours = 1;
+
+       p = pcap_create_common(device, ebuf, sizeof (struct pcap_can));
        if (p == NULL)
                return (NULL);
 
@@ -89,12 +145,12 @@ can_create(const char *device, char *ebuf)
 static int
 can_activate(pcap_t* handle)
 {
+       struct pcap_can *handlep = handle->priv;
        struct sockaddr_can addr;
        struct ifreq ifr;
 
        /* Initialize some components of the pcap structure. */
-       handle->bufsize = 24;
-       handle->offset = 8;
+       handle->bufsize = CAN_CONTROL_SIZE + 16;
        handle->linktype = DLT_CAN_SOCKETCAN;
        handle->read_op = can_read_linux;
        handle->inject_op = can_inject_linux;
@@ -109,29 +165,29 @@ can_activate(pcap_t* handle)
        handle->fd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
        if (handle->fd < 0)
        {
-               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s",
+               pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s",
                        errno, strerror(errno));
                return PCAP_ERROR;
        }
 
        /* get interface index */
        memset(&ifr, 0, sizeof(ifr));
-       strncpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name));
+       strlcpy(ifr.ifr_name, handle->opt.source, sizeof(ifr.ifr_name));
        if (ioctl(handle->fd, SIOCGIFINDEX, &ifr) < 0)
        {
-               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+               pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
                                "Unable to get interface index: %s",
                        pcap_strerror(errno));
                pcap_cleanup_live_common(handle);
                return PCAP_ERROR;
        }
-       handle->md.ifindex = ifr.ifr_ifindex;
+       handlep->ifindex = ifr.ifr_ifindex;
 
        /* allocate butter */
        handle->buffer = malloc(handle->bufsize);
        if (!handle->buffer)
        {
-               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s",
+               pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s",
                        pcap_strerror(errno));
                pcap_cleanup_live_common(handle);
                return PCAP_ERROR;
@@ -139,11 +195,11 @@ can_activate(pcap_t* handle)
 
        /* Bind to the socket */
        addr.can_family = AF_CAN;
-       addr.can_ifindex = handle->md.ifindex;
+       addr.can_ifindex = handlep->ifindex;
        if( bind( handle->fd, (struct sockaddr*)&addr, sizeof(addr) ) < 0  )
        {
-               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't attach to device %d %d:%s",
-                       handle->md.ifindex, errno, strerror(errno));
+               pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't attach to device %d %d:%s",
+                       handlep->ifindex, errno, strerror(errno));
                pcap_cleanup_live_common(handle);
                return PCAP_ERROR;
        }
@@ -152,7 +208,7 @@ can_activate(pcap_t* handle)
        {
                /* Monitor mode doesn't apply to CAN devices. */
                pcap_cleanup_live_common(handle);
-               return PCAP_ERROR;
+               return PCAP_ERROR_RFMON_NOTSUP;
        }
 
        handle->selectable_fd = handle->fd;
@@ -166,17 +222,19 @@ can_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *u
 {
        struct msghdr msg;
        struct pcap_pkthdr pkth;
+       u_char *pktd;
        struct iovec iv;
        struct can_frame* cf;
 
-       iv.iov_base = &handle->buffer[handle->offset];
+       pktd = (u_char *)handle->buffer + CAN_CONTROL_SIZE;
+       iv.iov_base = pktd;
        iv.iov_len = handle->snapshot;
 
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = &iv;
        msg.msg_iovlen = 1;
        msg.msg_control = handle->buffer;
-       msg.msg_controllen = handle->offset;
+       msg.msg_controllen = CAN_CONTROL_SIZE;
 
        do
        {
@@ -188,28 +246,28 @@ can_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *u
                }
        } while ((pkth.caplen == -1) && (errno == EINTR));
 
-       if (pkth.caplen < 0)
+       if (pkth.caplen == -1)
        {
-               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s",
+               pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s",
                        errno, strerror(errno));
                return -1;
        }
 
        /* adjust capture len according to frame len */
-       cf = (struct can_frame*)&handle->buffer[8];
-       pkth.caplen -= 8 - cf->can_dlc;
+       cf = (struct can_frame*)(void *)pktd;
+       pkth.caplen -= CAN_CONTROL_SIZE - cf->can_dlc;
        pkth.len = pkth.caplen;
 
        cf->can_id = htonl( cf->can_id );
 
        if( -1 == gettimeofday(&pkth.ts, NULL) )
        {
-               snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get time of day %d:%s",
+               pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't get time of day %d:%s",
                        errno, strerror(errno));
                return -1;
        }
 
-       callback(user, &pkth, &handle->buffer[8]);
+       callback(user, &pkth, pktd);
 
        return 1;
 }
@@ -219,7 +277,7 @@ static int
 can_inject_linux(pcap_t *handle, const void *buf, size_t size)
 {
        /* not yet implemented */
-       snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on "
+       pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on "
                "can devices");
        return (-1);
 }
@@ -250,7 +308,7 @@ can_setdirection_linux(pcap_t *p, pcap_direction_t d)
        /* no support for PCAP_D_OUT */
        if (d == PCAP_D_OUT)
        {
-               snprintf(p->errbuf, sizeof(p->errbuf),
+               pcap_snprintf(p->errbuf, sizeof(p->errbuf),
                        "Setting direction to PCAP_D_OUT is not supported on can");
                return -1;
        }