]> rtime.felk.cvut.cz Git - can-eth-gw.git/commitdiff
new options for cegwbench, first version of cesend
authorRadek Matejka <radek.matejka@gmail.com>
Wed, 8 Aug 2012 16:17:00 +0000 (18:17 +0200)
committerRadek Matejka <radek.matejka@gmail.com>
Wed, 8 Aug 2012 16:17:00 +0000 (18:17 +0200)
Cegwbench has now options to specify interfaces(can,udp) on which the
benchmark will be performed. The benchmark can be done in either
(can->eth,eth->can) direction. The benchmark modes are being introduced
(oneattime).

Cesend is a fork od cansend from Socket-CAN project. It sends a canframe
over udp.

utils/cegwbench/Makefile
utils/cegwbench/cegwbench.c
utils/cesend/Makefile [new file with mode: 0644]
utils/cesend/cesend.c [new file with mode: 0644]
utils/common/cegwerr.c [new file with mode: 0644]
utils/common/include/cegwerr.h [new file with mode: 0644]
utils/common/include/readif.h [new file with mode: 0644]
utils/common/readif.c [new file with mode: 0644]

index 68ca59ed123feb48df14184496f2bf643c9d37dd..07a7030ee264fd11701a2a173f7830b0ce1383cb 100644 (file)
@@ -1,3 +1,3 @@
 all:
-       gcc -Wall -ocegwbench -lrt cegwbench.c
+       gcc -Wall -ocegwbench -I../common/include -lrt cegwbench.c ../common/readif.c ../common/cegwerr.c
 
index dba10dda015b5dc206a27959dd5a8b1b34a4cb9a..7a93708011bbd10516821c90658c32d416d5d6e7 100644 (file)
@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <getopt.h>
 #include <time.h>
 #include <math.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <linux/can.h>
 #include <pthread.h>
+#include "cegwerr.h"
+#include "readif.h"
 
 /**
  * ToDo:
  * [ ] consider can timestamp
  */
 
+#define BENCH_FLAG_N 1
+#define BENCH_FLAG_SRC 2
+#define BENCH_FLAG_DST 4
+
+enum {
+       BENCH_MODE_UNDEF,
+       BENCH_MODE_ASAP,
+       BENCH_MODE_ONEATTIME,
+       BENCH_MODE_PERIOD
+};
+
+int can_sock_create( int ifindex );
+int udp_sock_create( struct in_addr ip, unsigned int port );
+
 struct optdata
 {
+       int optflag;
+       int mode;
        int n;
+       struct cegw_if ceif[2]; /* 0 -> src, 1 -> dst */
 };
 
 struct optdata d;
 pthread_barrier_t barrier;
 struct timespec* tx_time, * rx_time;
 
-void* udp_recv( void* arg )
+void* thr_recv( void* arg )
 {
-       struct sockaddr_in sa_udp;
-       int udp_sock;
+       int sock;
        struct can_frame cf;
        int i;
 
-       sa_udp.sin_family = AF_INET;
-       sa_udp.sin_port = htons( 10502 );
-       inet_aton( "127.0.0.1", &sa_udp.sin_addr );
-
-       udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       if( udp_sock < 0 )
-       {
-               fprintf( stderr, "error: udp socket creation failed\n" );
+       if( d.ceif[1].type == IF_CAN )
+               sock = can_sock_create( d.ceif[1].can.ifindex );
+       else
+               sock = udp_sock_create( d.ceif[1].eth.ip, d.ceif[1].eth.port );
+       if( sock == -1 )
                return NULL;
-       }
-
-       if( bind(udp_sock, (struct sockaddr*)&sa_udp, sizeof(sa_udp)) != 0 )
-       {
-               fprintf( stderr, "error: udp socket binding failed\n" );
-               return NULL;
-       }
 
        pthread_barrier_wait( &barrier );
 
        /* recv */
        for( i=0; i<d.n; i++ )
        {
-               recvfrom( udp_sock, &cf, sizeof(cf), 0, NULL, 0 );
+               recvfrom( sock, &cf, sizeof(cf), 0, NULL, 0 );
                clock_gettime( CLOCK_REALTIME, &rx_time[cf.data[0]] );
                printf( "recv: (id=%d)%u\n", cf.can_id, cf.data[0] );
+               if( d.mode == BENCH_MODE_ONEATTIME )
+               {
+                       pthread_barrier_wait( &barrier );
+               }
        }
 
-       close( udp_sock );
+       close( sock );
        return NULL;
 }
 
@@ -72,8 +85,9 @@ int timespec_subtract( struct timespec *result, struct timespec *x, struct times
                int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
                y->tv_nsec -= 1000000000 * nsec;
                y->tv_sec += nsec;
-               }
-       if (x->tv_nsec - y->tv_nsec > 1000000000) {
+       }
+       if (x->tv_nsec - y->tv_nsec > 1000000000)
+       {
                int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
                y->tv_nsec += 1000000000 * nsec;
                y->tv_sec -= nsec;
@@ -87,26 +101,126 @@ int timespec_subtract( struct timespec *result, struct timespec *x, struct times
        return x->tv_sec < y->tv_sec;
 }
 
+int udp_sock_create( struct in_addr ip, unsigned int port  )
+{
+       struct sockaddr_in addr_udp;
+       int udp_sock;
+
+       addr_udp.sin_family = AF_INET;
+       addr_udp.sin_port = htons( port );
+       addr_udp.sin_addr.s_addr = INADDR_ANY;
+
+       udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       if( udp_sock < 0 )
+       {
+               fprintf( stderr, "error: udp socket creation failed\n" );
+               return -1;
+       }
+
+       if( bind(udp_sock, (struct sockaddr*)&addr_udp, sizeof(addr_udp)) != 0 )
+       {
+               fprintf( stderr, "error: udp socket binding failed\n" );
+               return -1;
+       }
+
+       return udp_sock;
+}
+
+/**
+ * can_sock_create()
+ * @return can socket fd, or -1 on failure
+ */
+int can_sock_create( int ifindex )
+{
+       int can_sock;
+       struct sockaddr_can addr_can;
+
+       addr_can.can_family = AF_CAN;
+       addr_can.can_ifindex = ifindex;
+       
+       can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+       if( can_sock < 0 )
+       {
+               fprintf( stderr, "error: can socket creation failed\n" );
+               return -1;
+       }
+
+       if( bind(can_sock, (struct sockaddr*)&addr_can, sizeof(addr_can)) != 0 )
+       {
+               fprintf( stderr, "error: can socket binding failed\n" );
+               return -1;
+       }
+
+       return can_sock;
+}
+
+int read_mode( char* in )
+{
+       if( strcmp( in, "asap" ) == 0 )
+               return BENCH_MODE_ASAP;
+       if( strcmp( in, "oneattime") == 0 )
+               return BENCH_MODE_ONEATTIME;
+       if( strcmp( in, "period" ) == 0 )
+               return BENCH_MODE_PERIOD;
+
+       return BENCH_MODE_UNDEF;
+}
+
 int main( int argc, char* argv[] )
 {
        char opt;
-       struct sockaddr_can sa_can;
        struct can_frame cf;
-       int can_sock;
+       int sock;
        pthread_t thr;
        float mean = 0;
        float time;
+       int ret;
        struct timespec res;
-       int i;
+       int i, tmp;
+
+       d.optflag = 0;
+       d.mode = BENCH_MODE_ASAP;
+
+       struct option longopt[] =
+       {
+               { "mode", 0, NULL, 'm' },
+               { 0, 0, 0, 0 }
+       };
 
        while( 1 )
        {
-               opt = getopt( argc, argv, "n:" );
+               opt = getopt( argc, argv, "s:d:m:n:" );
                if( opt == -1 )
                        break;
                switch( opt )
                {
+                       case 's':
+                               d.optflag |= BENCH_FLAG_SRC;
+                               if( read_if( optarg, &d.ceif[0] ) != 0 )
+                               {
+                                       perr( "'-s'" );
+                                       return -1;
+                               }
+                               break;
+                       case 'd':
+                               d.optflag |= BENCH_FLAG_DST;
+                               if( read_if( optarg, &d.ceif[1] ) )
+                               {
+                                       perr( "-d" );
+                                       return -1;
+                               }
+                               break;
+                       case 'm':
+                               tmp = read_mode( optarg );
+                               if( tmp == BENCH_MODE_UNDEF )
+                               {
+                                       perr( "benchmarking mode unknown" );
+                                       return -1;
+                               }
+                               d.mode = tmp;
+                               break;
                        case 'n':
+                               d.optflag |= BENCH_FLAG_N;
                                d.n = atoi( optarg );
                                break;
                        case '?':
@@ -115,64 +229,109 @@ int main( int argc, char* argv[] )
                }
        }
 
+       /* check opt */
+       /* '-n' option is mandatory and its value is >0 */
+       if( d.optflag & BENCH_FLAG_N )
+       {
+               if( d.n < 1 )
+               {
+                       perr( "'-n' should be at least 1." );
+               }
+       } else 
+       {
+               perr( "'-n' is mandatory." );
+               return -1;
+       }
+
+       /* '-s' and '-d' should be defined and different iftype */
+       if( (d.optflag & BENCH_FLAG_SRC) && (d.optflag & BENCH_FLAG_DST) )
+       {
+               if( !(d.ceif[0].type == IF_CAN     && d.ceif[1].type == IF_ETH_UDP) &&
+                   !(d.ceif[0].type == IF_ETH_UDP && d.ceif[1].type == IF_CAN    )    )
+               {
+                       perr( "'-s' and '-d' should be different interface type." );
+                       return -1;
+               }
+       } else
+       {
+               perr( "'-s' and '-d' should be defined." );
+               return -1;
+       }
+
        tx_time = malloc( d.n*sizeof(struct timespec) );
        rx_time = malloc( d.n*sizeof(struct timespec) );
 
        pthread_barrier_init( &barrier, NULL, 2 );
-       pthread_create( &thr, NULL, udp_recv, NULL  );
+       pthread_create( &thr, NULL, thr_recv, NULL  );
 
-       sa_can.can_family = AF_CAN;
-       sa_can.can_ifindex = if_nametoindex( "vcan0" );
-       
-       can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
-       if( can_sock < 0 )
+       /**/
+       struct sockaddr* addr;
+       struct sockaddr_can addr_can;
+       struct sockaddr_in addr_udp;
+       int addr_size;
+
+       if( d.ceif[0].type == IF_CAN )
        {
-               fprintf( stderr, "error: can socket creation failed\n" );
-               return -1;
+               sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+               addr_can.can_family = AF_CAN;
+               addr_can.can_ifindex = d.ceif[0].can.ifindex;
+               addr = (struct sockaddr*)&addr_can;
+               addr_size = sizeof( addr_can );
        }
-
-       if( bind(can_sock, (struct sockaddr*)&sa_can, sizeof(sa_can)) != 0 )
+       else
        {
-               fprintf( stderr, "error: can socket binding failed\n" );
-               return -1;
+               sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+               addr_udp.sin_family = AF_INET;
+               addr_udp.sin_addr = d.ceif[0].eth.ip;
+               addr_udp.sin_port = htons( d.ceif[0].eth.port );
+               addr = (struct sockaddr*)&addr_udp;
+               addr_size = sizeof( addr_udp );
        }
+       if( sock < 0 ) /* ToDo: ? */
+               return -1;
 
        pthread_barrier_wait( &barrier );
 
        /* send  */
        for( i=0; i<d.n; i++ )
        {
-               //memset( &cf, 0, sizeof(cf) );
                cf.can_id = i;
                cf.can_dlc = 8;
                cf.data[0] = i;
-               int ret = sendto( can_sock, &cf, sizeof(cf), 0, (struct sockaddr*)&sa_can, sizeof(sa_can) );
+
                clock_gettime( CLOCK_REALTIME, &tx_time[cf.data[0]] );
+               ret = sendto( sock, &cf, sizeof(cf), 0, addr, addr_size );
                printf( "sending(%d)\n", ret );
+               if( d.mode == BENCH_MODE_ONEATTIME )
+               {
+                       pthread_barrier_wait( &barrier );
+               }
        }
 
-       close( can_sock ); /* shutdown? */
+       close( sock ); /* ToDo: shutdown? */
        pthread_join( thr, NULL );
 
        /* results */
+       int tn = 0;
        for( i=0; i<d.n; i++ )
        {
                if( timespec_subtract( &res, &rx_time[i], &tx_time[i] ) == 0 )
                {
                        time = res.tv_sec*1000000000.0f + (float)res.tv_nsec;
                        mean += time;
+                       tn++;
                        printf( "transfer time:%fns\n", time );
                } else
                {
                        printf( "transfer time: irrelevant\n" );
                }
        }
-       mean /= ++i;
+       mean /= tn; /* ToDo: did they arrive all? */
        printf( "average: %fns\n", mean );
 
+       pthread_barrier_destroy( &barrier );
        free( tx_time );
        free( rx_time );
-//     clock_gettime( CLOCK_REALTIME, &tx_time );
 
        return 0;
 }
diff --git a/utils/cesend/Makefile b/utils/cesend/Makefile
new file mode 100644 (file)
index 0000000..4e05b6f
--- /dev/null
@@ -0,0 +1,3 @@
+all:
+       gcc -Wall -ocesend cesend.c
+
diff --git a/utils/cesend/cesend.c b/utils/cesend/cesend.c
new file mode 100644 (file)
index 0000000..356ac84
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * cesend.c - simple command line tool to send CAN-frames via udp
+ * cesend is a fork of cansend from Socket-CAN project.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+
+#include <linux/can.h>
+#include <linux/can/raw.h>
+
+#define CANID_DELIM '#'
+#define DATA_SEPERATOR '.'
+
+unsigned char asc2nibble(char c) {
+
+       if ((c >= '0') && (c <= '9'))
+               return c - '0';
+
+       if ((c >= 'A') && (c <= 'F'))
+               return c - 'A' + 10;
+
+       if ((c >= 'a') && (c <= 'f'))
+               return c - 'a' + 10;
+
+       return 16; /* error */
+}
+
+int parse_canframe(char *cs, struct can_frame *cf) {
+       /* documentation see lib.h */
+
+       int i, idx, dlc, len;
+       unsigned char tmp;
+
+       len = strlen(cs);
+       //printf("'%s' len %d\n", cs, len);
+
+       memset(cf, 0, sizeof(*cf)); /* init CAN frame, e.g. DLC = 0 */
+
+       if (len < 4)
+               return 1;
+
+       if (cs[3] == CANID_DELIM) { /* 3 digits */
+
+               idx = 4;
+               for (i=0; i<3; i++){
+                       if ((tmp = asc2nibble(cs[i])) > 0x0F)
+                               return 1;
+                       cf->can_id |= (tmp << (2-i)*4);
+               }
+
+       } else if (cs[8] == CANID_DELIM) { /* 8 digits */
+
+               idx = 9;
+               for (i=0; i<8; i++){
+                       if ((tmp = asc2nibble(cs[i])) > 0x0F)
+                               return 1;
+                       cf->can_id |= (tmp << (7-i)*4);
+               }
+               if (!(cf->can_id & CAN_ERR_FLAG)) /* 8 digits but no errorframe?  */
+                       cf->can_id |= CAN_EFF_FLAG;   /* then it is an extended frame */
+
+       } else
+               return 1;
+
+       if((cs[idx] == 'R') || (cs[idx] == 'r')){ /* RTR frame */
+               cf->can_id |= CAN_RTR_FLAG;
+               return 0;
+       }
+
+       for (i=0, dlc=0; i<8; i++){
+
+               if(cs[idx] == DATA_SEPERATOR) /* skip (optional) seperator */
+                       idx++;
+
+               if(idx >= len) /* end of string => end of data */
+                       break;
+
+               if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+                       return 1;
+               cf->data[i] = (tmp << 4);
+               if ((tmp = asc2nibble(cs[idx++])) > 0x0F)
+                       return 1;
+               cf->data[i] |= tmp;
+               dlc++;
+       }
+
+       cf->can_dlc = dlc;
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int s; /* can raw socket */ 
+       int nbytes;
+       struct sockaddr_in addr;
+       struct can_frame frame;
+
+       /* check command line options */
+       if (argc != 2) {
+               fprintf(stderr, "Usage: %s <can_frame>.\n", argv[0]);
+               return 1;
+       }
+
+       /* parse CAN frame */
+       if (parse_canframe(argv[1], &frame)){
+               fprintf(stderr, "\nWrong CAN-frame format!\n\n");
+               fprintf(stderr, "Try: <can_id>#{R|data}\n");
+               fprintf(stderr, "can_id can have 3 (SFF) or 8 (EFF) hex chars\n");
+               fprintf(stderr, "data has 0 to 8 hex-values that can (optionally)");
+               fprintf(stderr, " be seperated by '.'\n\n");
+               fprintf(stderr, "e.g. 5A1#11.2233.44556677.88 / 123#DEADBEEF / ");
+               fprintf(stderr, "5AA# /\n     1F334455#1122334455667788 / 123#R ");
+               fprintf(stderr, "for remote transmission request.\n\n");
+               return 1;
+       }
+
+       /* open socket */
+       if(( s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 ) {
+               perror("socket");
+               return 1;
+       }
+
+       addr.sin_family = AF_INET;
+       inet_aton( "127.0.0.1", &addr.sin_addr );
+       addr.sin_port = htons( 10501 );
+
+       /* send frame */
+       if ((nbytes = sendto(s, &frame, sizeof(frame), 0, (struct sockaddr*)&addr, sizeof(addr))) != sizeof(frame)) {
+               perror("write");
+               return 1;
+       }
+
+       close(s);
+
+       return 0;
+}
+
diff --git a/utils/common/cegwerr.c b/utils/common/cegwerr.c
new file mode 100644 (file)
index 0000000..0a67978
--- /dev/null
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include "cegwerr.h"
+
+unsigned int cegw_errno = 0;
+
+char* cegw_errlist[] =
+{
+       [ CEGW_ERR_UNKNOWN   ] = "",
+       [ CEGW_ERR_IF_UNSPEC ] = "source or destination not specified",
+       [ CEGW_ERR_IF_SAME   ] = "source and destination have same interface type",
+       [ CEGW_ERR_IF_TYPE   ] = "unknown interface type",
+       [ CEGW_ERR_IF_CAN    ] = "invalid can interface",
+       [ CEGW_ERR_IF_ETH    ] = "invalid eth interface",
+       [ CEGW_ERR_COLON     ] = "expected ':' (<ip>:<port>)",
+       [ CEGW_ERR_ATON      ] = "ip address mismatch",
+       [ CEGW_ERR_PORT      ] = "port number"
+};
+
+void perr( char* s )
+{
+       if( s )
+       {
+               if( cegw_errno == 0 )
+               {
+                       fprintf( stderr, "error: %s\n", s );
+
+               } else
+               {
+                       fprintf( stderr, "error: %s, %s\n", s,
+                                cegw_errlist[ cegw_errno ] );
+               }
+               return;
+       }
+
+       fprintf( stderr, "error: %s\n", cegw_errlist[ cegw_errno ] );
+}
diff --git a/utils/common/include/cegwerr.h b/utils/common/include/cegwerr.h
new file mode 100644 (file)
index 0000000..99efc0e
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef CEGWERR_H
+#define CEGWERR_H
+
+extern unsigned int cegw_errno;
+extern char* cegw_errlist[];
+
+enum 
+{
+       CEGW_ERR_UNKNOWN,
+       CEGW_ERR_IF_UNSPEC,
+       CEGW_ERR_IF_SAME,
+       CEGW_ERR_IF_TYPE,
+       CEGW_ERR_IF_CAN,
+       CEGW_ERR_IF_ETH,
+       CEGW_ERR_COLON,
+       CEGW_ERR_ATON,
+       CEGW_ERR_PORT
+};
+
+void perr( char* s );
+
+#endif /* CEGWERR_H */
diff --git a/utils/common/include/readif.h b/utils/common/include/readif.h
new file mode 100644 (file)
index 0000000..c3f9dce
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef READIF_H
+#define READIF_H
+
+struct in_addr;
+
+enum
+{
+       IF_UNDEF,
+       IF_CAN,
+       IF_ETH_UDP
+};
+
+struct cegw_if
+{
+       int type;
+       union {
+               struct {
+                       struct in_addr ip;
+                       unsigned short port;
+               } eth;
+               struct {
+                        int ifindex;
+               } can;
+       };
+};
+
+int read_addrport( char* in, struct in_addr* addr, unsigned short* port );
+char* read_iftype( char* in, int* iftype );
+int read_if( char* in, struct cegw_if* ceif );
+
+#endif /* READIF_H */
diff --git a/utils/common/readif.c b/utils/common/readif.c
new file mode 100644 (file)
index 0000000..5ae5439
--- /dev/null
@@ -0,0 +1,161 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include "cegwerr.h"
+#include "readif.h"
+
+/**
+ * read_addrport - parses @in for eth address. 
+ * Valid input is e.g. udp@127.0.0.1:10502 or can@vcan0.
+ *
+ * @param[in]  in   string to search in
+ * @param[out] addr ip address
+ * @param[out] port transport layer port
+ * @return 0 on success, -1 otherwise
+ */
+int read_addrport( char* in, struct in_addr* addr, unsigned short* port )
+{
+       char* delim = NULL;
+       char addrstr[16];
+       int addrlen;
+
+       if( (delim = strchr( in, ':' )) == NULL )
+       {
+               cegw_errno = CEGW_ERR_COLON;
+               return -1;
+       }
+
+       /* get address */
+       addrlen = delim - in;
+       memcpy( addrstr, in, addrlen );
+       addrstr[addrlen] = '\0';
+       if( inet_aton( addrstr, addr ) == 0 )
+       {
+               cegw_errno = CEGW_ERR_ATON;
+               return -1;
+       }
+
+       /* get port */
+       if( sscanf( delim, ":%hu", port ) != 1 ) /* ToDo: handle overflow */
+       {
+               cegw_errno = CEGW_ERR_PORT;
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * read_iftype - reads @in for iftype
+ * Iftype type is e.g. "can@" or "udp@".
+ *
+ * @param[in] in string to search in
+ * @param[out] iftype iftype detected
+ * @return pointer to @in after iftype on success, NULL otherwise
+ */
+char* read_iftype( char* in, int* iftype )
+{
+       char* ret = in+4;
+       
+       if( strncmp( "udp@", optarg, 4 ) == 0 )
+       {
+               *iftype = IF_ETH_UDP;
+               return ret;
+       }
+       /*
+       if( strncmp( "tcp@", optarg, 4 ) == 0 )
+       {
+               return NULL;
+       }
+       */
+       if( strncmp( "can@", optarg, 4 ) == 0 )
+       {
+               *iftype = IF_CAN;
+               return ret;
+       }
+       
+       cegw_errno = CEGW_ERR_IF_TYPE;
+       return NULL;
+}
+
+/**
+ * read_if - reads interface from @in
+ * Function analyzes @in for interface specification in format
+ * <if>@<ip>:<port>, where <if> is can or udp, <ip> is address in dotted
+ * format.
+ *
+ * @param[in]  in string to search in
+ * @param[out] iftype interface type (IF_CAN or IF_ETH_UDP)
+ * @param[out] d ip and port is stored to @d
+ */
+
+/* ToDo: generalize
+int read_if( char* in, int* iftype, struct cegw_data* d )
+{
+       char* optstr = NULL;
+
+       if( (optstr = read_iftype( in, iftype )) == NULL )
+       {
+               return -1;
+       }
+
+       switch( *iftype )
+       {
+               case IF_CAN:
+                       d->can_ifidx = if_nametoindex( optstr );
+                       if( d->can_ifidx == 0 )
+                       {
+                               cegw_errno = CEGW_ERR_IF_CAN;
+                               return -1;
+                       }
+                       break;
+               case IF_ETH_UDP:
+                       if( read_addrport( optstr, &d->eth_addr, &d->eth_port ) != 0 )
+                       {
+                               return -1;
+                       }
+                       break;
+               default:
+                       return -1;
+                       break;
+       }
+
+       return 0;
+}
+*/
+
+int read_if( char* in, struct cegw_if* ceif )
+{
+       char* optstr = NULL;
+
+       if( (optstr = read_iftype( in, &ceif->type )) == NULL )
+       {
+               return -1;
+       }
+
+       switch( ceif->type )
+       {
+               case IF_CAN:
+                       ceif->can.ifindex = if_nametoindex( optstr );
+                       if( ceif->can.ifindex == 0 )
+                       {
+                               cegw_errno = CEGW_ERR_IF_CAN;
+                               return -1;
+                       }
+                       break;
+               case IF_ETH_UDP:
+                       if( read_addrport( optstr, &ceif->eth.ip, &ceif->eth.port ) != 0 )
+                       {
+                               return -1;
+                       }
+                       break;
+               default:
+                       return -1;
+                       break;
+       }
+
+       return 0;
+}