]> rtime.felk.cvut.cz Git - can-eth-gw.git/blobdiff - ppc/user/canethgw.c
PowerPC benchmark
[can-eth-gw.git] / ppc / user / canethgw.c
diff --git a/ppc/user/canethgw.c b/ppc/user/canethgw.c
new file mode 100644 (file)
index 0000000..09cae5c
--- /dev/null
@@ -0,0 +1,279 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <linux/can.h>
+#include <linux/can/raw.h>
+#include <poll.h>
+#include "readif.h"
+#include "cegwerr.h"
+
+/**
+ * ToDo:
+ * [ ] print usage
+ */
+//#define GW_DEBUG
+
+/* powerpc encore */
+#define AF_CAN 29
+#define PF_CAN AF_CAN
+
+#ifdef GW_DEBUG
+#define printdbg(x) printf(x)
+#else
+#define printdbg(x)
+#endif
+
+#define GW_POLL_ETH 0
+#define GW_POLL_CAN 1
+
+#define GW_FLAG_SRC 1
+#define GW_FLAG_DST 2
+#define GW_FLAG_LISTEN 4
+#define GW_FLAG_FILTER 8
+
+unsigned int opt_flag = 0;
+int sock_udp;
+int sock_can;
+struct can_filter flt;
+struct sockaddr_in udp_dest;
+
+/**
+ * filter_check
+ * @return true if frame should be dropped
+ */
+bool filter_check( struct can_frame* cf )
+{
+       if( !(opt_flag & GW_FLAG_FILTER) )
+               return false;
+
+       return ( (cf->can_id & flt.can_mask) == (flt.can_id & flt.can_mask) );
+}
+
+void send_to_can()
+{
+       struct can_frame cf;
+
+       read( sock_udp, &cf, sizeof(cf) );
+
+       if( filter_check( &cf ) )
+       {
+               printdbg( "filter: drop\n" );
+               return;
+       }
+       
+       write( sock_can, &cf, sizeof(cf) );
+       
+       printdbg( "eth -> can\n" );
+}
+
+void send_to_eth()
+{
+       struct can_frame cf;
+
+       read( sock_can, &cf, sizeof(cf) );
+
+       if( filter_check( &cf ) )
+       {
+               printdbg( "filter: drop\n" );
+               return;
+       }
+
+       sendto( sock_udp, &cf, sizeof(cf), 0, (struct sockaddr*) &udp_dest, sizeof(udp_dest) );
+
+       printdbg( "can -> eth\n" );
+}
+
+void signal_exit( int sig )
+{
+       close( sock_udp );
+       close( sock_can );
+       printf( "exiting\n" );
+
+       exit( 0 );
+}
+
+int main( int argc, char* argv[] )
+{
+       struct sockaddr_in udp_addr;
+       struct sockaddr_can can_addr;
+       struct pollfd pfd[2];
+       int polret;
+       int opt;
+       struct cegw_if ceif[2], iflisten;
+       struct cegw_if* ifcan,* ifeth;
+
+       flt.can_id = 0;
+       flt.can_mask = 0;
+
+       struct option longopt[] =
+       {
+               {"listen", 1, NULL, 'l'},
+               { 0, 0, 0, 0 }
+       };
+
+       while( (opt = getopt_long( argc, argv, "s:d:l:f:i:", longopt, NULL )) != -1 )
+       {
+               switch( opt )
+               {
+                       case 's':
+                               if( read_if(optarg, &ceif[0]) != 0 )
+                               {
+                                       perr( "'-s'" );
+                                       return -1;
+                               }
+                               opt_flag |= GW_FLAG_SRC;
+                               break;
+                       case 'd':
+                               if( read_if(optarg, &ceif[1]) != 0 )
+                               {
+                                       perr( "'-d'" );
+                                       return -1;
+                               }
+                               opt_flag |= GW_FLAG_DST;
+                               break;
+                       case 'l':
+                               if( read_if(optarg, &iflisten) != 0 )
+                               {                               
+                                       perr( "'-l'" );
+                                       return -1;
+                               }
+                               if( iflisten.type != IF_ETH_UDP )
+                               {
+                                       perr( "'-l' udp interface expected" );
+                                       return -1;
+                               }
+                               opt_flag |= GW_FLAG_LISTEN;
+                               break;
+                       case 'f':
+                               if( sscanf( optarg, "%x:%x", &flt.can_id,
+                                  &flt.can_mask ) != 2 ) 
+                               {
+                                       perr( "bad filter format");
+                                       return -1;
+                               }
+                               opt_flag |= GW_FLAG_FILTER;
+                               break;
+                       case '?':
+                               return -1;
+                               break;
+               }
+       }
+
+       if( !((opt_flag & GW_FLAG_SRC) && (opt_flag & GW_FLAG_DST) 
+               && (opt_flag & GW_FLAG_LISTEN)) )
+       {
+               perr( "'s', 'd' and 'l' are mandatory" ); 
+               /* ToDo: usage? */
+               return -1;
+       }
+
+       if( !(ceif[0].type == IF_CAN     && ceif[1].type == IF_ETH_UDP) &&
+           !(ceif[0].type == IF_ETH_UDP && ceif[1].type == IF_CAN    )    )
+       {
+               perr( "'-s' and '-d' should be different interface type" );
+               return -1;
+       }
+
+       if( ceif[0].type == IF_CAN )
+       {
+               ifcan = &ceif[0];
+               ifeth = &ceif[1];
+       } else
+       {
+               ifcan = &ceif[1];
+               ifeth = &ceif[0];
+       }
+
+       signal( SIGINT, signal_exit );
+
+       /* prepare udp destination */
+       udp_dest.sin_family = AF_INET;
+       udp_dest.sin_port = htons(ifeth->eth.port);
+       udp_dest.sin_addr = ifeth->eth.ip;
+
+       /* udp socket */
+       sock_udp = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       if( sock_udp < 0 )
+       {
+               perr( "udp socket creation failed" );
+               return -1;
+       }
+
+       udp_addr.sin_family = AF_INET;
+       udp_addr.sin_port = htons(iflisten.eth.port);
+       udp_addr.sin_addr = iflisten.eth.ip;
+
+       if( bind( sock_udp, (struct sockaddr*) &udp_addr, sizeof(udp_addr) ) < 0 )
+       {
+               perr( "udp socket binding failed" );
+               close( sock_udp );
+               return -1;
+       }
+
+       /* can socket */
+       sock_can = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+       if( sock_can < 0 )
+       {
+               perr( "can socket creation failed");
+               close( sock_can );
+               return -1;
+       }
+
+       can_addr.can_family = AF_CAN;
+       can_addr.can_ifindex = ifcan->can.ifindex;
+
+       if( bind( sock_can, (struct sockaddr*) &can_addr, sizeof(can_addr) ) < 0 )
+       {
+               perr( "can socket binding failed" );
+               return -1;
+       }
+
+       /* poll */
+       pfd[GW_POLL_ETH].fd = sock_udp;
+       pfd[GW_POLL_ETH].events = POLLIN | POLLPRI;
+       pfd[GW_POLL_ETH].revents = 0;
+
+       pfd[GW_POLL_CAN].fd = sock_can;
+       pfd[GW_POLL_CAN].events = POLLIN | POLLPRI;
+       pfd[GW_POLL_CAN].revents = 0;
+
+       printf( "canethgw is running\n" );
+
+       while( 1 )
+       {
+               printdbg( "polling\n" );
+               polret = poll( pfd, 2, -1 );
+               if( polret < 0 )
+               {
+                       perr( "poll(..) failed" );
+                       close( sock_udp );
+                       close( sock_can );
+                       return -1;
+               }
+
+               if( pfd[GW_POLL_ETH].revents != 0 )
+               {
+                       send_to_can();
+               }
+               if( pfd[GW_POLL_CAN].revents != 0 )
+               {
+                       send_to_eth();
+               }
+
+               pfd[GW_POLL_ETH].revents = 0;
+               pfd[GW_POLL_CAN].revents = 0;
+       }
+
+       return 0;
+}
+