]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/net/can/bcm.c
Add missinf includes for tasklet usage.
[socketcan-devel.git] / kernel / 2.6 / net / can / bcm.c
index b53c05b8f4ec498ce0c799207db48884e96bfffc..11c527953685126979ef3d6276256eef59d2a5d8 100644 (file)
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/hrtimer.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#include <linux/seq_file.h>
+#endif
 #include <linux/uio.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/socket.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
-#include <linux/can.h>
-#include <linux/can/core.h>
-#include <linux/can/bcm.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
+#include <socketcan/can/bcm.h>
 #include <net/sock.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
 #include "compat.h"
 #endif
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
+/*
+ * To send multiple CAN frame content within TX_SETUP or to filter
+ * CAN messages with multiplex index within RX_SETUP, the number of
+ * different filters is limited to 256 due to the one byte index value. 
+ */
+#define MAX_NFRAMES 256
+
 /* use of last_frames[index].can_dlc */
 #define RX_RECV    0x40 /* received data for this element */
 #define RX_THR     0x80 /* element not been sent due to throttle feature */
@@ -101,16 +112,16 @@ struct bcm_op {
        struct list_head list;
        int ifindex;
        canid_t can_id;
-       int flags;
+       u32 flags;
        unsigned long frames_abs, frames_filtered;
        struct timeval ival1, ival2;
        struct hrtimer timer, thrtimer;
        struct tasklet_struct tsklet, thrtsklet;
        ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
        int rx_ifindex;
-       int count;
-       int nframes;
-       int currframe;
+       u32 count;
+       u32 nframes;
+       u32 currframe;
        struct can_frame *frames;
        struct can_frame *last_frames;
        struct can_frame sframe;
@@ -130,7 +141,7 @@ struct bcm_sock {
        struct list_head tx_ops;
        unsigned long dropped_usr_msgs;
        struct proc_dir_entry *bcm_proc_read;
-       char procname [9]; /* pointer printed in ASCII with \0 */
+       char procname [32]; /* inode number in decimal with \0 */
 };
 
 static inline struct bcm_sock *bcm_sk(const struct sock *sk)
@@ -145,24 +156,114 @@ static inline struct bcm_sock *bcm_sk(const struct sock *sk)
 /*
  * procfs functions
  */
-static char *bcm_proc_getifname(int ifindex)
+static char *bcm_proc_getifname(char *result, int ifindex)
 {
        struct net_device *dev;
 
        if (!ifindex)
                return "any";
 
-       /* no usage counting */
+       read_lock(&dev_base_lock);
        dev = __dev_get_by_index(&init_net, ifindex);
        if (dev)
-               return dev->name;
+               strcpy(result, dev->name);
+       else
+               strcpy(result, "???");
+       read_unlock(&dev_base_lock);
+
+       return result;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+static int bcm_proc_show(struct seq_file *m, void *v)
+{
+       char ifname[IFNAMSIZ];
+       struct sock *sk = (struct sock *)m->private;
+       struct bcm_sock *bo = bcm_sk(sk);
+       struct bcm_op *op;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)
+       seq_printf(m, ">>> socket %p", sk->sk_socket);
+       seq_printf(m, " / sk %p", sk);
+       seq_printf(m, " / bo %p", bo);
+#else
+       seq_printf(m, ">>> socket %pK", sk->sk_socket);
+       seq_printf(m, " / sk %pK", sk);
+       seq_printf(m, " / bo %pK", bo);
+#endif
+       seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
+       seq_printf(m, " / bound %s", bcm_proc_getifname(ifname, bo->ifindex));
+       seq_printf(m, " <<<\n");
+
+       list_for_each_entry(op, &bo->rx_ops, list) {
+
+               unsigned long reduction;
+
+               /* print only active entries & prevent division by zero */
+               if (!op->frames_abs)
+                       continue;
+
+               seq_printf(m, "rx_op: %03X %-5s ",
+                               op->can_id, bcm_proc_getifname(ifname, op->ifindex));
+               seq_printf(m, "[%u]%c ", op->nframes,
+                               (op->flags & RX_CHECK_DLC)?'d':' ');
+               if (op->kt_ival1.tv64)
+                       seq_printf(m, "timeo=%lld ",
+                                       (long long)
+                                       ktime_to_us(op->kt_ival1));
+
+               if (op->kt_ival2.tv64)
+                       seq_printf(m, "thr=%lld ",
+                                       (long long)
+                                       ktime_to_us(op->kt_ival2));
+
+               seq_printf(m, "# recv %ld (%ld) => reduction: ",
+                               op->frames_filtered, op->frames_abs);
+
+               reduction = 100 - (op->frames_filtered * 100) / op->frames_abs;
 
-       return "???";
+               seq_printf(m, "%s%ld%%\n",
+                               (reduction == 100)?"near ":"", reduction);
+       }
+
+       list_for_each_entry(op, &bo->tx_ops, list) {
+
+               seq_printf(m, "tx_op: %03X %s [%u] ",
+                               op->can_id,
+                               bcm_proc_getifname(ifname, op->ifindex),
+                               op->nframes);
+
+               if (op->kt_ival1.tv64)
+                       seq_printf(m, "t1=%lld ",
+                                       (long long) ktime_to_us(op->kt_ival1));
+
+               if (op->kt_ival2.tv64)
+                       seq_printf(m, "t2=%lld ",
+                                       (long long) ktime_to_us(op->kt_ival2));
+
+               seq_printf(m, "# sent %ld\n", op->frames_abs);
+       }
+       seq_putc(m, '\n');
+       return 0;
+}
+
+static int bcm_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, bcm_proc_show, PDE(inode)->data);
 }
 
+static const struct file_operations bcm_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = bcm_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#else
 static int bcm_read_proc(char *page, char **start, off_t off,
                         int count, int *eof, void *data)
 {
+       char ifname[IFNAMSIZ];
        int len = 0;
        struct sock *sk = (struct sock *)data;
        struct bcm_sock *bo = bcm_sk(sk);
@@ -175,7 +276,7 @@ static int bcm_read_proc(char *page, char **start, off_t off,
        len += snprintf(page + len, PAGE_SIZE - len, " / dropped %lu",
                        bo->dropped_usr_msgs);
        len += snprintf(page + len, PAGE_SIZE - len, " / bound %s",
-                       bcm_proc_getifname(bo->ifindex));
+                       bcm_proc_getifname(ifname, bo->ifindex));
        len += snprintf(page + len, PAGE_SIZE - len, " <<<\n");
 
        list_for_each_entry(op, &bo->rx_ops, list) {
@@ -188,7 +289,7 @@ static int bcm_read_proc(char *page, char **start, off_t off,
 
                len += snprintf(page + len, PAGE_SIZE - len,
                                "rx_op: %03X %-5s ",
-                               op->can_id, bcm_proc_getifname(op->ifindex));
+                               op->can_id, bcm_proc_getifname(ifname, op->ifindex));
                len += snprintf(page + len, PAGE_SIZE - len, "[%d]%c ",
                                op->nframes,
                                (op->flags & RX_CHECK_DLC)?'d':' ');
@@ -224,7 +325,8 @@ static int bcm_read_proc(char *page, char **start, off_t off,
 
                len += snprintf(page + len, PAGE_SIZE - len,
                                "tx_op: %03X %s [%d] ",
-                               op->can_id, bcm_proc_getifname(op->ifindex),
+                               op->can_id,
+                               bcm_proc_getifname(ifname, op->ifindex),
                                op->nframes);
 
                if (op->kt_ival1.tv64)
@@ -250,6 +352,7 @@ static int bcm_read_proc(char *page, char **start, off_t off,
        *eof = 1;
        return len;
 }
+#endif
 
 /*
  * bcm_can_tx - send the (next) CAN frame to the appropriate CAN interface
@@ -304,7 +407,7 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
        struct can_frame *firstframe;
        struct sockaddr_can *addr;
        struct sock *sk = op->sk;
-       int datalen = head->nframes * CFSIZ;
+       unsigned int datalen = head->nframes * CFSIZ;
        int err;
 
        skb = alloc_skb(sizeof(*head) + datalen, gfp_any());
@@ -401,7 +504,7 @@ static void bcm_tx_timeout_tsklet(unsigned long data)
 }
 
 /*
- * bcm_tx_timeout_handler - performes cyclic CAN frame transmissions
+ * bcm_tx_timeout_handler - performs cyclic CAN frame transmissions
  */
 static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
 {
@@ -502,7 +605,7 @@ rx_changed_settime:
  * bcm_rx_cmp_to_index - (bit)compares the currently received data to formerly
  *                       received data stored in op->last_frames[]
  */
-static void bcm_rx_cmp_to_index(struct bcm_op *op, int index,
+static void bcm_rx_cmp_to_index(struct bcm_op *op, unsigned int index,
                                const struct can_frame *rxdata)
 {
        /*
@@ -588,7 +691,8 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
 /*
  * bcm_rx_do_flush - helper for bcm_rx_thr_flush
  */
-static inline int bcm_rx_do_flush(struct bcm_op *op, int update, int index)
+static inline int bcm_rx_do_flush(struct bcm_op *op, int update,
+                                 unsigned int index)
 {
        if ((op->last_frames) && (op->last_frames[index].can_dlc & RX_THR)) {
                if (update)
@@ -609,7 +713,7 @@ static int bcm_rx_thr_flush(struct bcm_op *op, int update)
        int updated = 0;
 
        if (op->nframes > 1) {
-               int i;
+               unsigned int i;
 
                /* for MUX filter we start at index 1 */
                for (i = 1; i < op->nframes; i++)
@@ -658,7 +762,7 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
 {
        struct bcm_op *op = (struct bcm_op *)data;
        const struct can_frame *rxframe = (struct can_frame *)skb->data;
-       int i;
+       unsigned int i;
 
        /* disable timeout */
        hrtimer_cancel(&op->timer);
@@ -858,14 +962,15 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
 {
        struct bcm_sock *bo = bcm_sk(sk);
        struct bcm_op *op;
-       int i, err;
+       unsigned int i;
+       int err;
 
        /* we need a real device to send frames */
        if (!ifindex)
                return -ENODEV;
 
-       /* we need at least one can_frame */
-       if (msg_head->nframes < 1)
+       /* check nframes boundaries - we need at least one can_frame */
+       if (msg_head->nframes < 1 || msg_head->nframes > MAX_NFRAMES)
                return -EINVAL;
 
        /* check the given can_id */
@@ -1029,6 +1134,10 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                msg_head->nframes = 0;
        }
 
+       /* the first element contains the mux-mask => MAX_NFRAMES + 1  */
+       if (msg_head->nframes > MAX_NFRAMES + 1)
+               return -EINVAL;
+
        if ((msg_head->flags & RX_RTR_FRAME) &&
            ((msg_head->nframes != 1) ||
             (!(msg_head->can_id & CAN_RTR_FLAG))))
@@ -1279,6 +1388,9 @@ static int bcm_sendmsg(struct kiocb *iocb, struct socket *sock,
                struct sockaddr_can *addr =
                        (struct sockaddr_can *)msg->msg_name;
 
+               if (msg->msg_namelen < sizeof(*addr))
+                       return -EINVAL;
+
                if (addr->can_family != AF_CAN)
                        return -EINVAL;
 
@@ -1452,9 +1564,14 @@ static int bcm_init(struct sock *sk)
 static int bcm_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       struct bcm_sock *bo = bcm_sk(sk);
+       struct bcm_sock *bo;
        struct bcm_op *op, *next;
 
+       if (sk == NULL)
+               return 0;
+
+       bo = bcm_sk(sk);
+
        /* remove bcm_ops, timer, rx_unregister(), etc. */
 
        unregister_netdevice_notifier(&bo->notifier);
@@ -1502,6 +1619,9 @@ static int bcm_release(struct socket *sock)
                bo->ifindex = 0;
        }
 
+       sock_orphan(sk);
+       sock->sk = NULL;
+
        release_sock(sk);
        sock_put(sk);
 
@@ -1515,6 +1635,9 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
        struct sock *sk = sock->sk;
        struct bcm_sock *bo = bcm_sk(sk);
 
+       if (len < sizeof(*addr))
+               return -EINVAL;
+
        if (bo->bound)
                return -EISCONN;
 
@@ -1543,10 +1666,16 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len,
 
        if (proc_dir) {
                /* unique socket address as filename */
-               sprintf(bo->procname, "%p", sock);
+               sprintf(bo->procname, "%lu", sock_i_ino(sk));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+               bo->bcm_proc_read = proc_create_data(bo->procname, 0644,
+                                                    proc_dir,
+                                                    &bcm_proc_fops, sk);
+#else
                bo->bcm_proc_read = create_proc_read_entry(bo->procname, 0644,
                                                           proc_dir,
                                                           bcm_read_proc, sk);
+#endif
        }
 
        return 0;
@@ -1588,7 +1717,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
        return size;
 }
 
-static struct proto_ops bcm_ops __read_mostly = {
+static const struct proto_ops bcm_ops = {
        .family        = PF_CAN,
        .release       = bcm_release,
        .bind          = sock_no_bind,
@@ -1597,7 +1726,7 @@ static struct proto_ops bcm_ops __read_mostly = {
        .accept        = sock_no_accept,
        .getname       = sock_no_getname,
        .poll          = datagram_poll,
-       .ioctl         = NULL,          /* use can_ioctl() from af_can.c */
+       .ioctl         = can_ioctl,     /* use can_ioctl() from af_can.c */
        .listen        = sock_no_listen,
        .shutdown      = sock_no_shutdown,
        .setsockopt    = sock_no_setsockopt,
@@ -1615,10 +1744,12 @@ static struct proto bcm_proto __read_mostly = {
        .init       = bcm_init,
 };
 
-static struct can_proto bcm_can_proto __read_mostly = {
+static const struct can_proto bcm_can_proto = {
        .type       = SOCK_DGRAM,
        .protocol   = CAN_BCM,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
        .capability = -1,
+#endif
        .ops        = &bcm_ops,
        .prot       = &bcm_proto,
 };