isotp: add tool support for ISO 15765-2:2015 with CAN FD upstream 0.1
authorOliver Hartkopp <socketcan@hartkopp.net>
Sun, 16 Nov 2014 21:24:04 +0000 (22:24 +0100)
committerOliver Hartkopp <socketcan@hartkopp.net>
Sun, 16 Nov 2014 21:24:04 +0000 (22:24 +0100)
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
include/linux/can/isotp.h
isotpdump.c
isotprecv.c
isotpsend.c

index 0381506..f074329 100644 (file)
@@ -66,6 +66,8 @@
                                        /* ignore received CF frames which */
                                        /* timestamps differ less than val */
 
                                        /* ignore received CF frames which */
                                        /* timestamps differ less than val */
 
+#define CAN_ISOTP_LL_OPTS      5       /* pass struct can_isotp_ll_options */
+
 struct can_isotp_options {
 
        __u32 flags;            /* set flags for isotp behaviour.       */
 struct can_isotp_options {
 
        __u32 flags;            /* set flags for isotp behaviour.       */
@@ -103,6 +105,24 @@ struct can_isotp_fc_options {
                                /* __u8 value : 0 = omit FC N_PDU WT    */
 };
 
                                /* __u8 value : 0 = omit FC N_PDU WT    */
 };
 
+struct can_isotp_ll_options {
+
+       __u8  mtu;              /* generated & accepted CAN frame type  */
+                               /* __u8 value :                         */
+                               /* CAN_MTU   (16) -> standard CAN 2.0   */
+                               /* CANFD_MTU (72) -> CAN FD frame       */
+
+       __u8  tx_dl;            /* tx link layer data length in bytes   */
+                               /* (configured maximum payload length)  */
+                               /* __u8 value : 8,12,16,20,24,32,48,64  */
+                               /* => rx path supports all LL_DL values */
+
+       __u8  tx_flags;         /* set into struct canfd_frame.flags    */
+                               /* at frame creation: e.g. CANFD_BRS    */
+                               /* Obsolete when the BRS flag is fixed  */
+                               /* by the CAN netdriver configuration   */
+};
+
 
 /* flags for isotp behaviour */
 
 
 /* flags for isotp behaviour */
 
@@ -122,13 +142,16 @@ struct can_isotp_fc_options {
 
 #define CAN_ISOTP_DEFAULT_FLAGS                0
 #define CAN_ISOTP_DEFAULT_EXT_ADDRESS  0x00
 
 #define CAN_ISOTP_DEFAULT_FLAGS                0
 #define CAN_ISOTP_DEFAULT_EXT_ADDRESS  0x00
-#define CAN_ISOTP_DEFAULT_RXPAD_CONTENT        0x00
-#define CAN_ISOTP_DEFAULT_TXPAD_CONTENT        0x00
+#define CAN_ISOTP_DEFAULT_PAD_CONTENT  0xCC /* prevent bit-stuffing */
 #define CAN_ISOTP_DEFAULT_FRAME_TXTIME 0
 #define CAN_ISOTP_DEFAULT_RECV_BS      0
 #define CAN_ISOTP_DEFAULT_RECV_STMIN   0x00
 #define CAN_ISOTP_DEFAULT_RECV_WFTMAX  0
 
 #define CAN_ISOTP_DEFAULT_FRAME_TXTIME 0
 #define CAN_ISOTP_DEFAULT_RECV_BS      0
 #define CAN_ISOTP_DEFAULT_RECV_STMIN   0x00
 #define CAN_ISOTP_DEFAULT_RECV_WFTMAX  0
 
+#define CAN_ISOTP_DEFAULT_LL_MTU       CAN_MTU
+#define CAN_ISOTP_DEFAULT_LL_TX_DL     CAN_MAX_DLEN
+#define CAN_ISOTP_DEFAULT_LL_TX_FLAGS  0
+
 /*
  * Remark on CAN_ISOTP_DEFAULT_RECV_* values:
  *
 /*
  * Remark on CAN_ISOTP_DEFAULT_RECV_* values:
  *
index 85be399..c5e9113 100644 (file)
@@ -60,6 +60,7 @@
 #define NO_CAN_ID 0xFFFFFFFFU
 
 const char fc_info [4][9] = { "CTS", "WT", "OVFLW", "reserved" };
 #define NO_CAN_ID 0xFFFFFFFFU
 
 const char fc_info [4][9] = { "CTS", "WT", "OVFLW", "reserved" };
+const int canfd_on = 1;
 
 void print_usage(char *prg)
 {
 
 void print_usage(char *prg)
 {
@@ -80,7 +81,7 @@ int main(int argc, char **argv)
        int s;
        struct sockaddr_can addr;
        struct can_filter rfilter[2];
        int s;
        struct sockaddr_can addr;
        struct can_filter rfilter[2];
-       struct can_frame frame;
+       struct canfd_frame frame;
        int nbytes, i;
        canid_t src = NO_CAN_ID;
        canid_t dst = NO_CAN_ID;
        int nbytes, i;
        canid_t src = NO_CAN_ID;
        canid_t dst = NO_CAN_ID;
@@ -180,6 +181,8 @@ int main(int argc, char **argv)
                return 1;
        }
 
                return 1;
        }
 
+       /* try to switch the socket into CAN FD mode */
+       setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on));
 
        if (src & CAN_EFF_FLAG) {
                rfilter[0].can_id   = src & (CAN_EFF_MASK | CAN_EFF_FLAG);
 
        if (src & CAN_EFF_FLAG) {
                rfilter[0].can_id   = src & (CAN_EFF_MASK | CAN_EFF_FLAG);
@@ -212,12 +215,12 @@ int main(int argc, char **argv)
        }
 
        while (1) {
        }
 
        while (1) {
-
-               if ((nbytes = read(s, &frame, sizeof(struct can_frame))) < 0) {
+               nbytes = read(s, &frame, sizeof(frame));
+               if (nbytes < 0) {
                        perror("read");
                        return 1;
                        perror("read");
                        return 1;
-               } else if (nbytes < sizeof(struct can_frame)) {
-                       fprintf(stderr, "read: incomplete CAN frame\n");
+               } else if (nbytes != CAN_MTU && nbytes != CANFD_MTU) {
+                       fprintf(stderr, "read: incomplete CAN frame %lu %d\n", sizeof(frame), nbytes);
                        return 1;
                } else {
 
                        return 1;
                } else {
 
@@ -284,15 +287,23 @@ int main(int argc, char **argv)
                        if (ext)
                                printf("{%02X}", frame.data[0]);
 
                        if (ext)
                                printf("{%02X}", frame.data[0]);
 
-                       printf("  [%d]  ", frame.can_dlc);
+                       if (nbytes == CAN_MTU)
+                               printf("  [%d]  ", frame.len);
+                       else
+                               printf(" [%02d]  ", frame.len);
 
                        datidx = 0;
                        n_pci = frame.data[ext];
            
                        switch (n_pci & 0xF0) {
                        case 0x00:
 
                        datidx = 0;
                        n_pci = frame.data[ext];
            
                        switch (n_pci & 0xF0) {
                        case 0x00:
-                               printf("[SF] ln: %-4d data:", n_pci & 0x0F);
-                               datidx = ext+1;
+                               if (n_pci & 0xF) {
+                                       printf("[SF] ln: %-4d data:", n_pci & 0xF);
+                                       datidx = ext+1;
+                               } else {
+                                       printf("[SF] ln: %-4d data:", frame.data[ext + 1]);
+                                       datidx = ext+2;
+                               }
                                break;
 
                        case 0x10:
                                break;
 
                        case 0x10:
@@ -341,16 +352,16 @@ int main(int argc, char **argv)
                                printf("[??]");
                        }
 
                                printf("[??]");
                        }
 
-                       if (datidx && frame.can_dlc > datidx) {
+                       if (datidx && frame.len > datidx) {
                                printf(" ");
                                printf(" ");
-                               for (i = datidx; i < frame.can_dlc; i++) {
+                               for (i = datidx; i < frame.len; i++) {
                                        printf("%02X ", frame.data[i]);
                                }
 
                                if (asc) {
                                        printf("%02X ", frame.data[i]);
                                }
 
                                if (asc) {
-                                       printf("%*s", ((7-ext) - (frame.can_dlc-datidx))*3 + 5 ,
+                                       printf("%*s", ((7-ext) - (frame.len-datidx))*3 + 5 ,
                                               "-  '");
                                               "-  '");
-                                       for (i = datidx; i < frame.can_dlc; i++) {
+                                       for (i = datidx; i < frame.len; i++) {
                                                printf("%c",((frame.data[i] > 0x1F) &&
                                                             (frame.data[i] < 0x7F))?
                                                       frame.data[i] : '.');
                                                printf("%c",((frame.data[i] > 0x1F) &&
                                                             (frame.data[i] < 0x7F))?
                                                       frame.data[i] : '.');
index a0934ba..f4b8610 100644 (file)
@@ -72,6 +72,7 @@ void print_usage(char *prg)
        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, "         -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, "         -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
        fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
        fprintf(stderr, "The pdu data is written on STDOUT in space separated ASCII hex values.\n");
        fprintf(stderr, "\n");
        fprintf(stderr, "\nCAN IDs and addresses are given and expected in hexadecimal values.\n");
        fprintf(stderr, "The pdu data is written on STDOUT in space separated ASCII hex values.\n");
        fprintf(stderr, "\n");
@@ -84,6 +85,7 @@ int main(int argc, char **argv)
     struct ifreq ifr;
     static struct can_isotp_options opts;
     static struct can_isotp_fc_options fcopts;
     struct ifreq ifr;
     static struct can_isotp_options opts;
     static struct can_isotp_fc_options fcopts;
+    static struct can_isotp_ll_options llopts;
     int opt, i;
     extern int optind, opterr, optopt;
     __u32 force_rx_stmin = 0;
     int opt, i;
     extern int optind, opterr, optopt;
     __u32 force_rx_stmin = 0;
@@ -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;
 
 
     addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
 
-    while ((opt = getopt(argc, argv, "s:d:x:X:p:P:b:m:w:f:l?")) != -1) {
+    while ((opt = getopt(argc, argv, "s:d:x:X:p:P:b:m:w:f:lL:?")) != -1) {
            switch (opt) {
            case 's':
                    addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
            switch (opt) {
            case 's':
                    addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
@@ -158,6 +160,17 @@ int main(int argc, char **argv)
                    loop = 1;
                    break;
 
                    loop = 1;
                    break;
 
+           case 'L':
+                   if (sscanf(optarg, "%hhu:%hhu:%hhu",
+                              &llopts.mtu,
+                              &llopts.tx_dl,
+                              &llopts.tx_flags) != 3) {
+                           printf("unknown link layer options '%s'.\n", optarg);
+                           print_usage(basename(argv[0]));
+                           exit(0);
+                   }
+                   break;
+
            case '?':
                    print_usage(basename(argv[0]));
                    exit(0);
            case '?':
                    print_usage(basename(argv[0]));
                    exit(0);
@@ -191,6 +204,13 @@ 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));
 
     setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
     setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &fcopts, sizeof(fcopts));
 
+    if (llopts.tx_dl) {
+       if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) {
+           perror("link layer sockopt");
+           exit(1);
+       }
+    }
+
     if (opts.flags & CAN_ISOTP_FORCE_RXSTMIN)
            setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RX_STMIN, &force_rx_stmin, sizeof(force_rx_stmin));
 
     if (opts.flags & CAN_ISOTP_FORCE_RXSTMIN)
            setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_RX_STMIN, &force_rx_stmin, sizeof(force_rx_stmin));
 
index 7b48ec2..2585bec 100644 (file)
@@ -70,6 +70,7 @@ void print_usage(char *prg)
        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, "         -D <len>     (send a fixed PDU with len bytes - no STDIN data)\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, "         -D <len>     (send a fixed PDU with len bytes - no STDIN data)\n");
+       fprintf(stderr, "         -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\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");
        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");
@@ -81,6 +82,7 @@ int main(int argc, char **argv)
     struct sockaddr_can addr;
     struct ifreq ifr;
     static struct can_isotp_options opts;
     struct sockaddr_can addr;
     struct ifreq ifr;
     static struct can_isotp_options opts;
+    static struct can_isotp_ll_options llopts;
     int opt;
     extern int optind, opterr, optopt;
     __u32 force_tx_stmin = 0;
     int opt;
     extern int optind, opterr, optopt;
     __u32 force_tx_stmin = 0;
@@ -91,7 +93,7 @@ int main(int argc, char **argv)
 
     addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
 
 
     addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
 
-    while ((opt = getopt(argc, argv, "s:d:x:X:p:P:t:f:D:?")) != -1) {
+    while ((opt = getopt(argc, argv, "s:d:x:X:p:P:t:f:D:L:?")) != -1) {
            switch (opt) {
            case 's':
                    addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
            switch (opt) {
            case 's':
                    addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
@@ -151,6 +153,17 @@ int main(int argc, char **argv)
                    }
                    break;
 
                    }
                    break;
 
+           case 'L':
+                   if (sscanf(optarg, "%hhu:%hhu:%hhu",
+                              &llopts.mtu,
+                              &llopts.tx_dl,
+                              &llopts.tx_flags) != 3) {
+                           printf("unknown link layer options '%s'.\n", optarg);
+                           print_usage(basename(argv[0]));
+                           exit(0);
+                   }
+                   break;
+
            case '?':
                    print_usage(basename(argv[0]));
                    exit(0);
            case '?':
                    print_usage(basename(argv[0]));
                    exit(0);
@@ -183,6 +196,13 @@ int main(int argc, char **argv)
 
     setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
 
 
     setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &opts, sizeof(opts));
 
+    if (llopts.tx_dl) {
+       if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) {
+           perror("link layer sockopt");
+           exit(1);
+       }
+    }
+
     if (opts.flags & CAN_ISOTP_FORCE_TXSTMIN)
            setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_TX_STMIN, &force_tx_stmin, sizeof(force_tx_stmin));
 
     if (opts.flags & CAN_ISOTP_FORCE_TXSTMIN)
            setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_TX_STMIN, &force_tx_stmin, sizeof(force_tx_stmin));