]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/net/can/bcm.c
can: add limit for nframes and clean up signed/unsigned variables
[socketcan-devel.git] / kernel / 2.6 / net / can / bcm.c
index 938d60be2cdcfa7a7607e2c4576830919686da20..1e4ac669120ccfdf9f702b277ffc537de8cb8e79 100644 (file)
@@ -47,6 +47,9 @@
 #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 <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 +111,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;
@@ -145,24 +155,108 @@ 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 "???";
+       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;
+
+       seq_printf(m, ">>> socket %p", sk->sk_socket);
+       seq_printf(m, " / sk %p", sk);
+       seq_printf(m, " / bo %p", bo);
+       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;
+
+               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 +269,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 +282,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 +318,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 +345,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 +400,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());
@@ -502,7 +598,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 +684,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 +706,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 +755,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 +955,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 +1127,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))))
@@ -1547,9 +1649,15 @@ 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);
+#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;