]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/net/can/bcm-prior-2-6-22.c
can bcm: fix tx_setup off-by-one errors
[socketcan-devel.git] / kernel / 2.6 / net / can / bcm-prior-2-6-22.c
index 6e435116d8843df51814cada7b2b851282361208..1254675b1729ab82ed3e6c969277e41ddf9219f4 100644 (file)
 #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>
 #include "compat.h"
 
-#include <linux/can/version.h> /* for RCSID. Removed by mkpatch script */
+#include <socketcan/can/version.h> /* for RCSID. Removed by mkpatch script */
 RCSID("$Id$");
 
 /* use of last_frames[index].can_dlc */
@@ -78,6 +78,7 @@ static __initdata const char banner[] = KERN_INFO
 MODULE_DESCRIPTION("PF_CAN broadcast manager protocol");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
+MODULE_ALIAS("can-proto-2");
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
 #error This code only supports Kernel versions _below_ 2.6.22
@@ -98,7 +99,11 @@ struct bcm_op {
        unsigned long frames_abs, frames_filtered;
        struct timeval ival1, ival2;
        struct timer_list timer, thrtimer;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+       struct skb_timeval rx_stamp;
+#else
        struct timeval rx_stamp;
+#endif
        unsigned long j_ival1, j_ival2, j_lastmsg;
        int rx_ifindex;
        int count;
@@ -361,7 +366,7 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
 
        if (has_timestamp) {
                /* restore rx timestamp */
-               skb_set_timestamp(skb, &op->rx_stamp);
+               skb->tstamp = op->rx_stamp;
        }
 
        /*
@@ -393,12 +398,12 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head,
 static void bcm_tx_timeout_handler(unsigned long data)
 {
        struct bcm_op *op = (struct bcm_op *)data;
+       struct bcm_msg_head msg_head;
 
        if (op->j_ival1 && (op->count > 0)) {
 
                op->count--;
                if (!op->count && (op->flags & TX_COUNTEVT)) {
-                       struct bcm_msg_head msg_head;
 
                        /* create notification to user */
                        msg_head.opcode  = TX_EXPIRED;
@@ -411,9 +416,6 @@ static void bcm_tx_timeout_handler(unsigned long data)
 
                        bcm_send_to_user(op, &msg_head, NULL, 0);
                }
-       }
-
-       if (op->j_ival1 && (op->count > 0)) {
 
                /* send (next) frame */
                bcm_can_tx(op);
@@ -427,8 +429,6 @@ static void bcm_tx_timeout_handler(unsigned long data)
                        mod_timer(&op->timer, jiffies + op->j_ival2);
                }
        }
-
-       return;
 }
 
 /*
@@ -447,6 +447,9 @@ static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data)
        if (op->frames_filtered > ULONG_MAX/100)
                op->frames_filtered = op->frames_abs = 0;
 
+       /* this element is not throttled anymore */
+       data->can_dlc &= (BCM_CAN_DLC_MASK|RX_RECV);
+
        head.opcode  = RX_CHANGED;
        head.flags   = op->flags;
        head.count   = op->count;
@@ -465,23 +468,20 @@ static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data)
  */
 static void bcm_rx_update_and_send(struct bcm_op *op,
                                   struct can_frame *lastdata,
-                                  struct can_frame *rxdata)
+                                  const struct can_frame *rxdata)
 {
        unsigned long nexttx = op->j_lastmsg + op->j_ival2;
 
        memcpy(lastdata, rxdata, CFSIZ);
 
-       /* mark as used */
-       lastdata->can_dlc |= RX_RECV;
+       /* mark as used and throttled by default */
+       lastdata->can_dlc |= (RX_RECV|RX_THR);
 
        /* throttle bcm_rx_changed ? */
        if ((op->thrtimer.expires) ||
            ((op->j_ival2) && (nexttx > jiffies))) {
                /* we are already waiting OR we have to start waiting */
 
-               /* mark as 'throttled' */
-               lastdata->can_dlc |= RX_THR;
-
                if (!(op->thrtimer.expires)) {
                        /* start the timer only the first time */
                        mod_timer(&op->thrtimer, nexttx);
@@ -489,7 +489,7 @@ static void bcm_rx_update_and_send(struct bcm_op *op,
 
        } else {
                /* send RX_CHANGED to the user immediately */
-               bcm_rx_changed(op, rxdata);
+               bcm_rx_changed(op, lastdata);
        }
 }
 
@@ -498,7 +498,7 @@ static void bcm_rx_update_and_send(struct bcm_op *op,
  *                       received data stored in op->last_frames[]
  */
 static void bcm_rx_cmp_to_index(struct bcm_op *op, int index,
-                               struct can_frame *rxdata)
+                               const struct can_frame *rxdata)
 {
        /*
         * no one uses the MSBs of can_dlc for comparation,
@@ -550,6 +550,7 @@ static void bcm_rx_timeout_handler(unsigned long data)
        struct bcm_op *op = (struct bcm_op *)data;
        struct bcm_msg_head msg_head;
 
+       /* create notification to user */
        msg_head.opcode  = RX_TIMEOUT;
        msg_head.flags   = op->flags;
        msg_head.count   = op->count;
@@ -569,6 +570,18 @@ static void bcm_rx_timeout_handler(unsigned long data)
        }
 }
 
+/*
+ * bcm_rx_do_flush - helper for bcm_rx_thr_flush
+ */
+static inline int bcm_rx_do_flush(struct bcm_op *op, int index)
+{
+       if ((op->last_frames) && (op->last_frames[index].can_dlc & RX_THR)) {
+               bcm_rx_changed(op, &op->last_frames[index]);
+               return 1;
+       }
+       return 0;
+}
+
 /*
  * bcm_rx_thr_flush - Check for throttled data and send it to the userspace
  */
@@ -580,22 +593,12 @@ static int bcm_rx_thr_flush(struct bcm_op *op)
                int i;
 
                /* for MUX filter we start at index 1 */
-               for (i = 1; i < op->nframes; i++) {
-                       if ((op->last_frames) &&
-                           (op->last_frames[i].can_dlc & RX_THR)) {
-                               op->last_frames[i].can_dlc &= ~RX_THR;
-                               bcm_rx_changed(op, &op->last_frames[i]);
-                               updated++;
-                       }
-               }
+               for (i = 1; i < op->nframes; i++)
+                       updated += bcm_rx_do_flush(op, i);
 
        } else {
                /* for RX_FILTER_ID and simple filter */
-               if (op->last_frames && (op->last_frames[0].can_dlc & RX_THR)) {
-                       op->last_frames[0].can_dlc &= ~RX_THR;
-                       bcm_rx_changed(op, &op->last_frames[0]);
-                       updated++;
-               }
+               updated += bcm_rx_do_flush(op, 0);
        }
 
        return updated;
@@ -623,29 +626,21 @@ static void bcm_rx_thr_handler(unsigned long data)
 static void bcm_rx_handler(struct sk_buff *skb, void *data)
 {
        struct bcm_op *op = (struct bcm_op *)data;
-       struct can_frame rxframe;
+       const struct can_frame *rxframe = (struct can_frame *)skb->data;
        int i;
 
        /* disable timeout */
        del_timer(&op->timer);
 
-       if (skb->len == sizeof(rxframe)) {
-               memcpy(&rxframe, skb->data, sizeof(rxframe));
-               /* save rx timestamp */
-               skb_get_timestamp(skb, &op->rx_stamp);
-               /* save originator for recvfrom() */
-               op->rx_ifindex = skb->dev->ifindex;
-               /* update statistics */
-               op->frames_abs++;
-               kfree_skb(skb);
-
-       } else {
-               kfree_skb(skb);
+       if (op->can_id != rxframe->can_id)
                return;
-       }
 
-       if (op->can_id != rxframe.can_id)
-               return;
+       /* save rx timestamp */
+       op->rx_stamp = skb->tstamp;
+       /* save originator for recvfrom() */
+       op->rx_ifindex = skb->dev->ifindex;
+       /* update statistics */
+       op->frames_abs++;
 
        if (op->flags & RX_RTR_FRAME) {
                /* send reply for RTR-request (placed in op->frames[0]) */
@@ -655,16 +650,14 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
 
        if (op->flags & RX_FILTER_ID) {
                /* the easiest case */
-               bcm_rx_update_and_send(op, &op->last_frames[0], &rxframe);
-               bcm_rx_starttimer(op);
-               return;
+               bcm_rx_update_and_send(op, &op->last_frames[0], rxframe);
+               goto rx_starttimer;
        }
 
        if (op->nframes == 1) {
                /* simple compare with index 0 */
-               bcm_rx_cmp_to_index(op, 0, &rxframe);
-               bcm_rx_starttimer(op);
-               return;
+               bcm_rx_cmp_to_index(op, 0, rxframe);
+               goto rx_starttimer;
        }
 
        if (op->nframes > 1) {
@@ -676,15 +669,17 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
                 */
 
                for (i = 1; i < op->nframes; i++) {
-                       if ((GET_U64(&op->frames[0]) & GET_U64(&rxframe)) ==
+                       if ((GET_U64(&op->frames[0]) & GET_U64(rxframe)) ==
                            (GET_U64(&op->frames[0]) &
                             GET_U64(&op->frames[i]))) {
-                               bcm_rx_cmp_to_index(op, i, &rxframe);
+                               bcm_rx_cmp_to_index(op, i, rxframe);
                                break;
                        }
                }
-               bcm_rx_starttimer(op);
        }
+
+rx_starttimer:
+       bcm_rx_starttimer(op);
 }
 
 /*
@@ -960,15 +955,19 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                /* spec: send can_frame when starting timer */
                op->flags |= TX_ANNOUNCE;
 
-               if (op->j_ival1 && (op->count > 0)) {
+               /* only start timer when having more frames than sent below */
+               if (op->j_ival1 && (op->count > 1)) {
                        /* op->count-- is done in bcm_tx_timeout_handler */
                        mod_timer(&op->timer, jiffies + op->j_ival1);
                } else
                        mod_timer(&op->timer, jiffies + op->j_ival2);
        }
 
-       if (op->flags & TX_ANNOUNCE)
+       if (op->flags & TX_ANNOUNCE) {
                bcm_can_tx(op);
+               if (op->j_ival1 && (op->count > 0))
+                       op->count--;
+       }
 
        return msg_head->nframes * CFSIZ + MHSIZ;
 }
@@ -1458,6 +1457,9 @@ static int bcm_release(struct socket *sock)
                bo->ifindex = 0;
        }
 
+       sock_orphan(sk);
+       sock->sk = NULL;
+
        release_sock(sk);
        sock_put(sk);
 
@@ -1544,7 +1546,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,
@@ -1553,7 +1555,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,
@@ -1572,7 +1574,7 @@ 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,
        .capability = -1,
@@ -1580,7 +1582,7 @@ static struct can_proto bcm_can_proto __read_mostly = {
        .prot       = &bcm_proto,
 };
 #else
-static struct can_proto bcm_can_proto __read_mostly = {
+static const struct can_proto bcm_can_proto = {
        .type       = SOCK_DGRAM,
        .protocol   = CAN_BCM,
        .capability = -1,