]> rtime.felk.cvut.cz Git - can-utils.git/blobdiff - isotptun.c
candump: Enable HW timestamping before using it
[can-utils.git] / isotptun.c
index 5fca673703abd7201ef08d61325fd661bfb407df..fc2a8d57bf2fc81201c2c06d895d439667946c5b 100644 (file)
@@ -1,7 +1,3 @@
-/*
- *  $Id$
- */
-
 /*
  * isotptun.c - IP over CAN ISO-TP (ISO15765-2) tunnel / proof-of-concept
  *
@@ -47,7 +43,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
  *
- * Send feedback to <socketcan-users@lists.berlios.de>
+ * Send feedback to <linux-can@vger.kernel.org>
  *
  */
 
@@ -58,6 +54,7 @@
 #include <string.h>
 #include <libgen.h>
 #include <errno.h>
+#include <signal.h>
 
 #include <net/if.h>
 #include <sys/types.h>
 #include <linux/if_tun.h>
 
 #define NO_CAN_ID 0xFFFFFFFFU
+#define DEFAULT_NAME "ctun%d"
+
+/* stay on 4095 bytes for the max. PDU length which is still much more than the standard ethernet MTU */
+#define MAX_PDU_LENGTH 4095
+#define BUF_LEN (MAX_PDU_LENGTH + 1)
+
+static volatile int running = 1;
 
 void print_usage(char *prg)
 {
@@ -77,10 +81,11 @@ void print_usage(char *prg)
        fprintf(stderr, "ethernet frames inside ISO15765-2 (unreliable) datagrams on CAN.\n\n");
        fprintf(stderr, "Options: -s <can_id>  (source can_id. Use 8 digits for extended IDs)\n");
        fprintf(stderr, "         -d <can_id>  (destination can_id. Use 8 digits for extended IDs)\n");
-       fprintf(stderr, "         -x <addr>    (extended addressing mode.)\n");
-       fprintf(stderr, "         -p <byte>    (padding byte rx path)\n");
-       fprintf(stderr, "         -q <byte>    (padding byte tx path)\n");
-       fprintf(stderr, "         -P <mode>    (check padding. (l)ength (c)ontent (a)ll)\n");
+       fprintf(stderr, "         -n <name>    (name of created IP netdevice. Default: '%s')\n", DEFAULT_NAME);
+       fprintf(stderr, "         -x <addr>[:<rxaddr>] (extended addressing / opt. separate rxaddr)\n");
+       fprintf(stderr, "         -L <mtu>:<tx_dl>:<tx_flags> (link layer options for CAN FD)\n");
+       fprintf(stderr, "         -p [tx]:[rx] (set and enable tx/rx padding bytes)\n");
+       fprintf(stderr, "         -P <mode>    (check rx padding for (l)ength (c)ontent (a)ll)\n");
        fprintf(stderr, "         -t <time ns> (transmit time in nanosecs)\n");
        fprintf(stderr, "         -b <bs>      (blocksize. 0 = off)\n");
        fprintf(stderr, "         -m <val>     (STmin in ms/ns. See spec.)\n");
@@ -93,6 +98,11 @@ void print_usage(char *prg)
        fprintf(stderr, "\n");
 }
 
+void sigterm(int signo)
+{
+       running = 0;
+}
+
 int main(int argc, char **argv)
 {
        fd_set rdfs;
@@ -101,17 +111,21 @@ int main(int argc, char **argv)
        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, ret;
        extern int optind, opterr, optopt;
-       static int quit;
        static int verbose;
-
-       unsigned char buffer[4096];
+       unsigned char buffer[BUF_LEN];
+       static char name[IFNAMSIZ] = DEFAULT_NAME;
        int nbytes;
 
+       signal(SIGTERM, sigterm);
+       signal(SIGHUP, sigterm);
+       signal(SIGINT, sigterm);
+
        addr.can_addr.tp.tx_id = addr.can_addr.tp.rx_id = NO_CAN_ID;
 
-       while ((opt = getopt(argc, argv, "s:d:x:p:q:P:t:b:m:whv")) != -1) {
+       while ((opt = getopt(argc, argv, "s:d:n:x:p:P:t:b:m:whL:v?")) != -1) {
                switch (opt) {
                case 's':
                        addr.can_addr.tp.tx_id = strtoul(optarg, (char **)NULL, 16);
@@ -125,20 +139,47 @@ int main(int argc, char **argv)
                                addr.can_addr.tp.rx_id |= CAN_EFF_FLAG;
                        break;
 
-               case 'x':
-                       opts.flags |= CAN_ISOTP_EXTEND_ADDR;
-                       opts.ext_address = strtoul(optarg, (char **)NULL, 16) & 0xFF;
+               case 'n':
+                       strncpy(name, optarg, IFNAMSIZ-1);
                        break;
 
-               case 'p':
-                       opts.flags |= CAN_ISOTP_RX_PADDING;
-                       opts.rxpad_content = strtoul(optarg, (char **)NULL, 16) & 0xFF;
+               case 'x':
+               {
+                       int elements = sscanf(optarg, "%hhx:%hhx",
+                                             &opts.ext_address,
+                                             &opts.rx_ext_address);
+
+                       if (elements == 1)
+                               opts.flags |= CAN_ISOTP_EXTEND_ADDR;
+                       else if (elements == 2)
+                               opts.flags |= (CAN_ISOTP_EXTEND_ADDR | CAN_ISOTP_RX_EXT_ADDR);
+                       else {
+                               printf("incorrect extended addr values '%s'.\n", optarg);
+                               print_usage(basename(argv[0]));
+                               exit(0);
+                       }
                        break;
+               }
 
-               case 'q':
-                       opts.flags |= CAN_ISOTP_TX_PADDING;
-                       opts.txpad_content = strtoul(optarg, (char **)NULL, 16) & 0xFF;
+               case 'p':
+               {
+                       int elements = sscanf(optarg, "%hhx:%hhx",
+                                             &opts.txpad_content,
+                                             &opts.rxpad_content);
+
+                       if (elements == 1)
+                               opts.flags |= CAN_ISOTP_TX_PADDING;
+                       else if (elements == 2)
+                               opts.flags |= (CAN_ISOTP_TX_PADDING | CAN_ISOTP_RX_PADDING);
+                       else if (sscanf(optarg, ":%hhx", &opts.rxpad_content) == 1)
+                               opts.flags |= CAN_ISOTP_RX_PADDING;
+                       else {
+                               printf("incorrect padding values '%s'.\n", optarg);
+                               print_usage(basename(argv[0]));
+                               exit(0);
+                       }
                        break;
+               }
 
                case 'P':
                        if (optarg[0] == 'l')
@@ -146,7 +187,7 @@ int main(int argc, char **argv)
                        else if (optarg[0] == 'c')
                                opts.flags |= CAN_ISOTP_CHK_PAD_DATA;
                        else if (optarg[0] == 'a')
-                               opts.flags |= (CAN_ISOTP_CHK_PAD_DATA | CAN_ISOTP_CHK_PAD_DATA);
+                               opts.flags |= (CAN_ISOTP_CHK_PAD_LEN | CAN_ISOTP_CHK_PAD_DATA);
                        else {
                                printf("unknown padding check option '%c'.\n", optarg[0]);
                                print_usage(basename(argv[0]));
@@ -174,14 +215,30 @@ int main(int argc, char **argv)
                        opts.flags |= CAN_ISOTP_HALF_DUPLEX;
                        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 'v':
                        verbose = 1;
                        break;
 
+               case '?':
+                       print_usage(basename(argv[0]));
+                       exit(0);
+                       break;
+
                default:
                        fprintf(stderr, "Unknown option %c\n", opt);
                        print_usage(basename(argv[0]));
-                       exit(0);
+                       exit(1);
                        break;
                }
        }
@@ -190,7 +247,7 @@ int main(int argc, char **argv)
            (addr.can_addr.tp.tx_id == NO_CAN_ID) ||
            (addr.can_addr.tp.rx_id == NO_CAN_ID)) {
                print_usage(basename(argv[0]));
-               exit(0);
+               exit(1);
        }
   
        if ((s = socket(PF_CAN, SOCK_DGRAM, CAN_ISOTP)) < 0) {
@@ -201,9 +258,22 @@ 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 (llopts.tx_dl) {
+               if (setsockopt(s, SOL_CAN_ISOTP, CAN_ISOTP_LL_OPTS, &llopts, sizeof(llopts)) < 0) {
+                       perror("link layer sockopt");
+                       exit(1);
+               }
+       }
+
+       strncpy(ifr.ifr_name, argv[optind], IFNAMSIZ);
+       ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);
+       if (!ifr.ifr_ifindex) {
+               perror("if_nametoindex");
+               close(s);
+               exit(1);
+       }
+
        addr.can_family = AF_CAN;
-       strcpy(ifr.ifr_name, argv[optind]);
-       ioctl(s, SIOCGIFINDEX, &ifr);
        addr.can_ifindex = ifr.ifr_ifindex;
 
        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
@@ -221,7 +291,8 @@ int main(int argc, char **argv)
 
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
-       strncpy(ifr.ifr_name, "ctun%d", IFNAMSIZ);
+       strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
+       ifr.ifr_name[IFNAMSIZ - 1] = '\0';
 
        if (ioctl(t, TUNSETIFF, (void *) &ifr) < 0) {
                perror("ioctl tunfd");
@@ -230,31 +301,24 @@ int main(int argc, char **argv)
                exit(1);
        }
 
-       while (!quit) {
+       while (running) {
 
                FD_ZERO(&rdfs);
                FD_SET(s, &rdfs);
                FD_SET(t, &rdfs);
-               FD_SET(0, &rdfs);
 
                if ((ret = select(t+1, &rdfs, NULL, NULL, NULL)) < 0) {
                        perror("select");
                        continue;
                }
 
-               if (FD_ISSET(0, &rdfs)) {
-                       getchar();
-                       quit = 1;
-                       printf("quit due to keyboard input.\n");
-               }
-
                if (FD_ISSET(s, &rdfs)) {
-                       nbytes = read(s, buffer, 4096);
+                       nbytes = read(s, buffer, BUF_LEN);
                        if (nbytes < 0) {
                                perror("read isotp socket");
                                return -1;
                        }
-                       if (nbytes > 4095)
+                       if (nbytes > MAX_PDU_LENGTH)
                                return -1;
                        ret = write(t, buffer, nbytes);
                        if (verbose) {
@@ -267,12 +331,12 @@ int main(int argc, char **argv)
                }
 
                if (FD_ISSET(t, &rdfs)) {
-                       nbytes = read(t, buffer, 4096);
+                       nbytes = read(t, buffer, BUF_LEN);
                        if (nbytes < 0) {
                                perror("read tunfd");
                                return -1;
                        }
-                       if (nbytes > 4095)
+                       if (nbytes > MAX_PDU_LENGTH)
                                return -1;
                        ret = write(s, buffer, nbytes);
                        if (verbose) {