X-Git-Url: http://rtime.felk.cvut.cz/gitweb/socketcan-devel.git/blobdiff_plain/6c0ce3f01b578e1fc761f4c37e851c3d6ab75833..05e2d5c0adda7e44b9afb6d6a17d1dbe90af4488:/kernel/2.6/net/can/isotp.c diff --git a/kernel/2.6/net/can/isotp.c b/kernel/2.6/net/can/isotp.c index 1e0f14d..f15f788 100644 --- a/kernel/2.6/net/can/isotp.c +++ b/kernel/2.6/net/can/isotp.c @@ -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 #include #include +#include +#include #include #include #include @@ -61,9 +63,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) #include @@ -72,7 +74,7 @@ #include "compat.h" #endif -#include /* for RCSID. Removed by mkpatch script */ +#include /* 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 "); +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, };