]> rtime.felk.cvut.cz Git - socketcan-devel.git/blobdiff - kernel/2.6/net/can/isotp.c
Add missinf includes for tasklet usage.
[socketcan-devel.git] / kernel / 2.6 / net / can / isotp.c
index 1e0f14d5e02d93dcd8fb03c2f679c75893ae1eab..f15f788a34d113e42efd8732fa3c858e297cb2ed 100644 (file)
@@ -2,7 +2,7 @@
  * isotp.c - ISO 15765-2 CAN transport protocol for protocol family CAN
  *
  * WARNING: This is ALPHA code for discussions and first tests that should
- *          not be used in productive environments.
+ *          not be used in production environments.
  *
  * In the discussion the Socket-API to the userspace or the ISO-TP socket
  * options or the return values we may change! Current behaviour:
@@ -54,6 +54,8 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
 #include <linux/wait.h>
 #include <linux/uio.h>
 #include <linux/net.h>
@@ -61,9 +63,9 @@
 #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/isotp.h>
+#include <socketcan/can.h>
+#include <socketcan/can/core.h>
+#include <socketcan/can/isotp.h>
 #include <net/sock.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
 #include <net/net_namespace.h>
@@ -72,7 +74,7 @@
 #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$");
 
 #define CAN_ISOTP_VERSION CAN_VERSION
@@ -82,6 +84,7 @@ static __initdata const char banner[] =
 MODULE_DESCRIPTION("PF_CAN isotp 15765-2 protocol");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
+MODULE_ALIAS("can-proto-6");
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
 #error This modules needs hrtimers (available since Kernel 2.6.22)
@@ -131,10 +134,13 @@ struct isotp_sock {
        canid_t txid;
        canid_t rxid;
        ktime_t tx_gap;
+       ktime_t lastrxcf_tstamp;
        struct hrtimer rxtimer, txtimer;
        struct tasklet_struct txtsklet;
        struct can_isotp_options opt;
        struct can_isotp_fc_options rxfc, txfc;
+       __u32 force_tx_stmin;
+       __u32 force_rx_stmin;
        struct tpcon rx, tx;
        struct notifier_block notifier;
        wait_queue_head_t wait;
@@ -210,6 +216,9 @@ static int isotp_send_fc(struct sock *sk, int ae)
        /* reset blocksize counter */
        so->rx.bs = 0;
 
+       /* reset last CF frame rx timestamp for rx stmin enforcement */
+       so->lastrxcf_tstamp = ktime_set(0,0);
+
        /* start rx timeout watchdog */
        hrtimer_start(&so->rxtimer, ktime_set(1,0), HRTIMER_MODE_REL);
        return 0;
@@ -279,7 +288,10 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct can_frame *cf, int ae)
                /* add transmission time for CAN frame N_As */
                so->tx_gap = ktime_add_ns(so->tx_gap, so->opt.frame_txtime);
                /* add waiting time for consecutive frames N_Cs */
-               if (so->txfc.stmin < 0x80)
+               if (so->opt.flags & CAN_ISOTP_FORCE_TXSTMIN) 
+                       so->tx_gap = ktime_add_ns(so->tx_gap,
+                                                 so->force_tx_stmin);
+               else if (so->txfc.stmin < 0x80)
                        so->tx_gap = ktime_add_ns(so->tx_gap,
                                                  so->txfc.stmin * 1000000);
                else
@@ -396,6 +408,16 @@ static int isotp_rcv_cf(struct sock *sk, struct can_frame *cf, int ae,
        if (so->rx.state != ISOTP_WAIT_DATA)
                return 0;
 
+       /* drop if timestamp gap is less than force_rx_stmin nano secs */
+       if (so->opt.flags & CAN_ISOTP_FORCE_RXSTMIN) {
+
+               if (ktime_to_ns(ktime_sub(skb->tstamp, so->lastrxcf_tstamp)) <
+                   so->force_rx_stmin)
+                       return 0;
+
+               so->lastrxcf_tstamp = skb->tstamp; 
+       }
+
        hrtimer_cancel(&so->rxtimer);
 
        if ((cf->data[ae] & 0x0F) != so->rx.sn) {
@@ -775,7 +797,12 @@ static int isotp_recvmsg(struct kiocb *iocb, struct socket *sock,
 static int isotp_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       struct isotp_sock *so = isotp_sk(sk);
+       struct isotp_sock *so;
+
+       if (!sk)
+               return 0;
+
+       so = isotp_sk(sk);
 
        /* wait for complete transmission of current pdu */
        wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
@@ -806,6 +833,9 @@ static int isotp_release(struct socket *sock)
        so->ifindex = 0;
        so->bound   = 0;
 
+       sock_orphan(sk);
+       sock->sk = NULL;
+
        release_sock(sk);
        sock_put(sk);
 
@@ -911,8 +941,13 @@ static int isotp_getname(struct socket *sock, struct sockaddr *uaddr,
        return 0;
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+static int isotp_setsockopt(struct socket *sock, int level, int optname,
+                           char __user *optval, unsigned int optlen)
+#else
 static int isotp_setsockopt(struct socket *sock, int level, int optname,
                            char __user *optval, int optlen)
+#endif
 {
        struct sock *sk = sock->sk;
        struct isotp_sock *so = isotp_sk(sk);
@@ -941,6 +976,22 @@ static int isotp_setsockopt(struct socket *sock, int level, int optname,
                        return -EFAULT;
                break;
 
+       case CAN_ISOTP_TX_STMIN:
+               if (optlen != sizeof(__u32))
+                       return -EINVAL;
+
+               if (copy_from_user(&so->force_tx_stmin, optval, optlen))
+                       return -EFAULT;
+               break;
+
+       case CAN_ISOTP_RX_STMIN:
+               if (optlen != sizeof(__u32))
+                       return -EINVAL;
+
+               if (copy_from_user(&so->force_rx_stmin, optval, optlen))
+                       return -EFAULT;
+               break;
+
        default:
                ret = -ENOPROTOOPT;
        }
@@ -975,6 +1026,16 @@ static int isotp_getsockopt(struct socket *sock, int level, int optname,
                val = &so->rxfc;
                break;
 
+       case CAN_ISOTP_TX_STMIN:
+               len = min_t(int, len, sizeof(__u32));
+               val = &so->force_tx_stmin;
+               break;
+
+       case CAN_ISOTP_RX_STMIN:
+               len = min_t(int, len, sizeof(__u32));
+               val = &so->force_rx_stmin;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
@@ -1072,7 +1133,7 @@ static int isotp_init(struct sock *sk)
 }
 
 
-static struct proto_ops isotp_ops __read_mostly = {
+static const struct proto_ops isotp_ops = {
        .family        = PF_CAN,
        .release       = isotp_release,
        .bind          = isotp_bind,
@@ -1081,7 +1142,7 @@ static struct proto_ops isotp_ops __read_mostly = {
        .accept        = sock_no_accept,
        .getname       = isotp_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    = isotp_setsockopt,
@@ -1099,10 +1160,12 @@ static struct proto isotp_proto __read_mostly = {
        .init       = isotp_init,
 };
 
-static struct can_proto isotp_can_proto __read_mostly = {
+static const struct can_proto isotp_can_proto = {
        .type       = SOCK_DGRAM,
        .protocol   = CAN_ISOTP,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
        .capability = -1,
+#endif
        .ops        = &isotp_ops,
        .prot       = &isotp_proto,
 };