]> rtime.felk.cvut.cz Git - socketcan-devel.git/commitdiff
Added new socketoptions to force the isotp protocol to intentionally
authorhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Sun, 14 Nov 2010 08:55:06 +0000 (08:55 +0000)
committerhartkopp <hartkopp@030b6a49-0b11-0410-94ab-b0dab22257f2>
Sun, 14 Nov 2010 08:55:06 +0000 (08:55 +0000)
misbehave for regression tests.

CAN_ISOTP_TX_STMIN:
Set a value in nano secs that's used as minimum CF gap by the sender.
This value is used instead of the value provided by the receiver inside the FC.

CAN_ISOTP_RX_STMIN:
Ignores received CF frames which timestamps differ less than this value in nano
secs. This is used to test the receivers misbehaviour when the receiver
provides a lower stmin value that he's able to cope with. Received CF frames
are silently dropped when they come faster than specified by this value.

git-svn-id: svn://svn.berlios.de//socketcan/trunk@1201 030b6a49-0b11-0410-94ab-b0dab22257f2

can-utils/isotprecv.c
can-utils/isotpsend.c
kernel/2.6/include/socketcan/can/isotp.h
kernel/2.6/net/can/isotp.c

index 9e37c86829c726964df7fa3667a95fb4b2dd26e4..acd6de6acca52cf85213d6a167864fc672558bec 100644 (file)
@@ -71,6 +71,7 @@ void print_usage(char *prg)
        fprintf(stderr, "         -P <mode>    (check padding in SF/CF. (l)ength (c)ontent (a)ll)\n");
        fprintf(stderr, "         -b <bs>      (blocksize. 0 = off)\n");
        fprintf(stderr, "         -m <val>     (STmin in ms/ns. See spec.)\n");
+       fprintf(stderr, "         -f <time ns> (force rx stmin value in nanosecs)\n");
        fprintf(stderr, "         -w <num>     (max. wait frame transmissions.)\n");
        fprintf(stderr, "         -l           (loop: do not exit after pdu receiption.)\n");
        fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
@@ -87,6 +88,7 @@ int main(int argc, char **argv)
     static struct can_isotp_fc_options fcopts;
     int opt, i;
     extern int optind, opterr, optopt;
+    __u32 force_rx_stmin = 0;
     int loop = 0;
 
     unsigned char msg[4096];
@@ -94,7 +96,7 @@ int main(int argc, char **argv)
 
     addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
 
-    while ((opt = getopt(argc, argv, "s:d:x:p:P:b:m:w:l?")) != -1) {
+    while ((opt = getopt(argc, argv, "s:d:x:p:P:b:m:w:f:l?")) != -1) {
            switch (opt) {
            case 's':
                    addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
@@ -144,6 +146,11 @@ int main(int argc, char **argv)
                    fcopts.wftmax = strtoul(optarg, (char **)NULL, 16) & 0xFF;
                    break;
 
+           case 'f':
+                   opts.flags |= CAN_ISOTP_FORCE_RXSTMIN;
+                   force_rx_stmin = strtoul(optarg, (char **)NULL, 10);
+                   break;
+
            case 'l':
                    loop = 1;
                    break;
@@ -176,6 +183,9 @@ int main(int argc, char **argv)
     setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
     setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts));
 
+    if (opts.flags & CAN_ISOTP_FORCE_RXSTMIN)
+           setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RX_STMIN, &force_rx_stmin, sizeof(force_rx_stmin));
+
     addr.can_family = AF_CAN;
     strcpy(ifr.ifr_name, argv[optind]);
     ioctl(s, SIOCGIFINDEX, &ifr);
index bcaa35ba7ff3e690853ee7b85e5fa0ea115a26b2..015dca6bab4d934ee3e87047324e748a1d5da94a 100644 (file)
@@ -69,7 +69,8 @@ void print_usage(char *prg)
        fprintf(stderr, "         -x <addr>    (extended addressing mode. Use 'any' for all addresses)\n");
        fprintf(stderr, "         -p <byte>    (set and enable padding byte)\n");
        fprintf(stderr, "         -P <mode>    (check padding in FC. (l)ength (c)ontent (a)ll)\n");
-       fprintf(stderr, "         -t <time ns> (transmit time in nanosecs)\n");
+       fprintf(stderr, "         -t <time ns> (frame transmit time (N_As) in nanosecs)\n");
+       fprintf(stderr, "         -f <time ns> (ignore FC and force local tx stmin value in nanosecs)\n");
        fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
        fprintf(stderr, "The pdu data is expected on STDIN in space separated ASCII hex values.\n");
        fprintf(stderr, "\n");
@@ -83,12 +84,13 @@ int main(int argc, char **argv)
     static struct can_isotp_options opts;
     int opt;
     extern int optind, opterr, optopt;
+    __u32 force_tx_stmin = 0;
     unsigned char buf[4096];
     int buflen = 0;
 
     addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
 
-    while ((opt = getopt(argc, argv, "s:d:x:p:P:t:?")) != -1) {
+    while ((opt = getopt(argc, argv, "s:d:x:p:P:t:f:?")) != -1) {
            switch (opt) {
            case 's':
                    addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
@@ -130,6 +132,11 @@ int main(int argc, char **argv)
                    opts.frame_txtime = strtoul(optarg, (char **)NULL, 10);
                    break;
 
+           case 'f':
+                   opts.flags |= CAN_ISOTP_FORCE_TXSTMIN;
+                   force_tx_stmin = strtoul(optarg, (char **)NULL, 10);
+                   break;
+
            case '?':
                    print_usage(basename(argv[0]));
                    exit(0);
@@ -157,6 +164,9 @@ int main(int argc, char **argv)
 
     setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
 
+    if (opts.flags & CAN_ISOTP_FORCE_TXSTMIN)
+           setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_TX_STMIN, &force_tx_stmin, sizeof(force_tx_stmin));
+
     addr.can_family = AF_CAN;
     strcpy(ifr.ifr_name, argv[optind]);
     ioctl(s, SIOCGIFINDEX, &ifr);
index 361dc300cf5747b968320838eefddc547fce4292..4c90ac8ba2353b8b212a48f05648c7c4bf1fafe9 100644 (file)
 
 /* for socket options affecting the socket (not the global system) */
 
-#define CAN_ISOTP_OPTS         1
-#define CAN_ISOTP_RECV_FC      2
+#define CAN_ISOTP_OPTS         1       /* pass struct can_isotp_options */
+
+#define CAN_ISOTP_RECV_FC      2       /* pass struct can_isotp_fc_options */
+
+/* sockopts to force stmin timer values for protocol regression tests */
+
+#define CAN_ISOTP_TX_STMIN     3       /* pass __u32 value in nano secs    */
+                                       /* use this time instead of value   */
+                                       /* provided in FC from the receiver */
+
+#define CAN_ISOTP_RX_STMIN     4       /* pass __u32 value in nano secs   */
+                                       /* ignore received CF frames which */
+                                       /* timestamps differ less than val */
 
 struct can_isotp_options {
 
@@ -62,13 +73,15 @@ struct can_isotp_fc_options {
 
 /* flags for isotp behaviour */
 
-#define CAN_ISOTP_LISTEN_MODE  0x01    /* listen only (do not send FC) */
-#define CAN_ISOTP_EXTEND_ADDR  0x02    /* enable extended addressing */
-#define CAN_ISOTP_TX_PADDING   0x04    /* enable CAN frame padding tx path */
-#define CAN_ISOTP_RX_PADDING   0x08    /* enable CAN frame padding rx path */
-#define CAN_ISOTP_CHK_PAD_LEN  0x10    /* check received CAN frame padding */
-#define CAN_ISOTP_CHK_PAD_DATA 0x20    /* check received CAN frame padding */
-#define CAN_ISOTP_HALF_DUPLEX  0x40    /* half duplex error state handling */
+#define CAN_ISOTP_LISTEN_MODE  0x001   /* listen only (do not send FC) */
+#define CAN_ISOTP_EXTEND_ADDR  0x002   /* enable extended addressing */
+#define CAN_ISOTP_TX_PADDING   0x004   /* enable CAN frame padding tx path */
+#define CAN_ISOTP_RX_PADDING   0x008   /* enable CAN frame padding rx path */
+#define CAN_ISOTP_CHK_PAD_LEN  0x010   /* check received CAN frame padding */
+#define CAN_ISOTP_CHK_PAD_DATA 0x020   /* check received CAN frame padding */
+#define CAN_ISOTP_HALF_DUPLEX  0x040   /* half duplex error state handling */
+#define CAN_ISOTP_FORCE_TXSTMIN        0x080   /* ignore stmin from received FC */
+#define CAN_ISOTP_FORCE_RXSTMIN        0x100   /* ignore CFs depending on rx stmin */
 
 
 /* default values */
index b93e51d69716bf3b65babf37c43d9c08566a4928..4d7f98b0e6ffae9b2f81c4e1cbb4e230c87198b3 100644 (file)
@@ -132,10 +132,13 @@ struct isotp_sock {
        canid_t txid;
        canid_t rxid;
        ktime_t tx_gap;
+       ktime_t last_cf_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;
@@ -276,11 +279,17 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct can_frame *cf, int ae)
                    ((so->txfc.stmin < 0xF1) || (so->txfc.stmin > 0xF9)))
                        so->txfc.stmin = 0x7F;
 
+               /* reset CF frame rx timestamp for rx stmin enforcement */
+               so->last_cf_tstamp = ktime_set(0,0);
+
                so->tx_gap = ktime_set(0,0);
                /* 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
@@ -397,6 +406,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->last_cf_tstamp)) <
+                   so->force_rx_stmin)
+                       return 0;
+
+               so->last_cf_tstamp = skb->tstamp; 
+       }
+
        hrtimer_cancel(&so->rxtimer);
 
        if ((cf->data[ae] & 0x0F) != so->rx.sn) {
@@ -950,6 +969,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;
        }
@@ -984,6 +1019,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;
        }