]> rtime.felk.cvut.cz Git - can-eth-gw.git/commitdiff
cegw refactor
authorRadek Matejka <radek.matejka@gmail.com>
Thu, 26 Jul 2012 16:10:45 +0000 (18:10 +0200)
committerRadek Matejka <radek.matejka@gmail.com>
Thu, 26 Jul 2012 16:10:45 +0000 (18:10 +0200)
kernel/canethgw.c
kernel/canethgw.h
utils/cegw/cegw.c

index 992ded96ff50ba235af17fa47c7a03537026e4ca..88f2614e935f251fc2669c20f45e5c147ee61f17 100644 (file)
@@ -194,8 +194,7 @@ inline static void gw_can_send( struct can_frame* cf, int ifidx )
 
 /* NetLink */
 
-static int cgw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh,
-                     void* arg )
+static int cegw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg )
 {
        struct nlattr* tb[ CGW_MAX+1 ];
        struct rtcanmsg *r;
@@ -259,6 +258,29 @@ static int cgw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh,
        return 0;
 }
 
+static int cegw_remove_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg )
+{
+       struct rtcanmsg* r;
+       struct nlattr* tb[ CGW_MAX+1 ];
+
+       if( nlmsg_len(nlh) < sizeof(*r) )
+               return -EINVAL;
+       
+       r = nlmsg_data( nlh );
+
+       if( r->can_family != AF_CAN )
+               return -EPFNOSUPPORT;
+
+       if( r->gwtype != CGW_TYPE_CAN_ETH_UDP )
+               return -EINVAL;
+
+       printk( "flags:%x",r->flags );
+       //nlmsg_parse( nlh, sizeof(*r), tb, CGW_MAX, NULL );
+
+       //      tb[]
+       return 0;
+}
+
 static int listen( int can_ifidx, struct in_addr eth_addr, u16 eth_port )
 {
        struct sockaddr_in udp_addr;
@@ -331,7 +353,8 @@ static int __init cangw_init( void )
        
        /* subscribe to netlink */
        //if( __rtnl_register( PF_CAN, RTM_GETROUTE,  ) != 0 )
-       __rtnl_register( PF_CAN, RTM_NEWROUTE, cgw_create_job, NULL, NULL );
+       __rtnl_register( PF_CAN, RTM_NEWROUTE, cegw_create_job, NULL, NULL );
+       __rtnl_register( PF_CAN, RTM_DELROUTE, cegw_remove_job, NULL, NULL );
        //__rtnl_register( PF_CAN, RTM_DELROUTE,  )     
        
        /*
@@ -353,6 +376,7 @@ static void __exit cangw_exit( void )
                /* ToDo: stop threads */
        }
 
+       /* ToDo: unregister netlink */
        printk( "cangw: exit\n" );
        //kthread_stop( ts );
 }
index f09a42084cda276694e7de92ff5c0bff1058f5aa..cfcd1b69770b17bdd7fcfcb89550988332cf6d5f 100644 (file)
@@ -21,6 +21,10 @@ enum {
        __CGW_TYPE_MAX
 };
 
+enum {
+       CEGW_FLUSH
+};
+
 #define CGW_TYPE_MAX (__CGW_TYPE_MAX - 1)
 
 enum {
index 275d6592ff91864c9707ce0acf1787efa68b6c29..efbe2c775bcc4e1dd711d6535199a1fa1a4a14fc 100644 (file)
  * 
  */
 
-#define CMD_STOP_LISTEN    1
-#define CMD_START_LISTEN   2
-#define CMD_ADD_RULE       4
+#define CEGW_CMD_ADD     1
+#define CEGW_CMD_LIST    2
+#define CEGW_CMD_FLUSH   4
+#define CEGW_CMD_LISTEN  8
 
-enum {
+enum
+{
        IF_UNDEF,
        IF_CAN,
        IF_ETH_UDP
 };
 
+struct cegw_data
+{
+       int content;
+       int src_if, dst_if;
+       int can_ifidx;
+       struct in_addr eth_addr;
+       unsigned short eth_port;
+       struct in_addr eth_listen_addr;
+       unsigned short eth_listen_port;
+};
+
+struct cegw_nlmsg 
+{
+       struct nlmsghdr nh;
+       struct rtcanmsg rtcan;
+       char buf[600]; /* enough? */
+};
+
+unsigned int cegw_errno = 0;
+
+enum 
+{
+       CEGW_ERR_UNKNOWN,
+       CEGW_ERR_IF_UNSPEC,
+       CEGW_ERR_IF_SAME,
+       CEGW_ERR_IF_TYPE
+};
+
+char* cegw_errlist[] =
+{
+       [ CEGW_ERR_UNKNOWN ]   = "unknown error",
+       [ 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"
+};
+
+static void perr( char* s )
+{
+       if( s )
+       {
+               fprintf( stderr, "error: %s; %s\n", s,
+               cegw_errlist[ cegw_errno ] );
+               return;
+       }
+
+       fprintf( stderr, "error: %s\n", cegw_errlist[ cegw_errno ] );
+}
 
 /**
- * parses @in for eth address, valid input is 
- * e.g. udp@127.0.0.1:10502 or can@vcan0
+ * Parses @in for eth address. Valid input is 
+ * e.g. udp@127.0.0.1:10502 or can@vcan0.
  *
  * @param[out] addr ip address
  * @param[out] port transport layer port
@@ -74,6 +123,13 @@ int read_addr_port( char* in, struct in_addr* addr, unsigned short* port )
        return 0;
 }
 
+/**
+ * Reads @in for iftype (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;
@@ -83,48 +139,130 @@ char* read_iftype( char* in, int* iftype )
                *iftype = IF_ETH_UDP;
                return ret;
        }
+       /*
        else if( strncmp( "tcp@", optarg, 4 ) == 0 )
        {
                return NULL;
        }
+       */
        else if( strncmp( "can@", optarg, 4 ) == 0 )
        {
                *iftype = IF_CAN;
                return ret;
        }
        
+       errno = CEGW_ERR_IF_TYPE;
        return NULL;
 }
 
+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 );
+                       break;
+               case IF_ETH_UDP:
+                       read_addr_port( optstr, &d->eth_addr, &d->eth_port );
+                       break;
+               default:
+                       return -1;
+                       break;
+       }
+
+       return 0;
+}
+
+inline static int cegw_add( struct cegw_nlmsg* req, struct cegw_data* d )
+{
+       req->nh.nlmsg_type  = RTM_NEWROUTE;
+       if( (d->src_if == 0 || d->dst_if == 0) )
+       {
+               cegw_errno = CEGW_ERR_IF_UNSPEC;
+               return -cegw_errno;
+       }
+
+       if( d->src_if == d->dst_if )
+       {
+               cegw_errno = CEGW_ERR_IF_SAME;
+               return -cegw_errno;
+       }
+
+       req->rtcan.gwtype = (d->src_if == IF_CAN) ? CGW_TYPE_CAN_ETH_UDP : CGW_TYPE_ETH_CAN_UDP;
+       addattr_l( &req->nh, sizeof(*req), CGW_CAN_IF, &d->can_ifidx, sizeof(d->can_ifidx) );
+       switch( req->rtcan.gwtype )
+       {
+               case CGW_TYPE_CAN_ETH_UDP:
+                       addattr_l( &req->nh, sizeof(*req), CGW_ETH_IP, &d->eth_addr, sizeof(d->eth_addr) );
+                       addattr_l( &req->nh, sizeof(*req), CGW_ETH_PORT, &d->eth_port, sizeof(d->eth_port) );
+                       break;
+               case CGW_TYPE_ETH_CAN_UDP:
+                       break;
+               default:
+                       break;
+       }
+
+       return 0;
+}
+
+inline static int cegw_listen( struct cegw_nlmsg* req, struct cegw_data* d )
+{
+       req->nh.nlmsg_type  = RTM_NEWROUTE;
+       req->rtcan.gwtype = CGW_TYPE_CONFIG;
+       addattr_l( &req->nh, sizeof(req), CGW_LISTEN_IP, &d->eth_listen_addr, sizeof(d->eth_listen_addr) );
+       addattr_l( &req->nh, sizeof(req), CGW_LISTEN_PORT, &d->eth_listen_port, sizeof(d->eth_listen_port) );
+       printf( "start listen: %x, %hu\n", d->eth_listen_addr, d->eth_listen_port );
+
+       return 0;
+}
+
+inline static int cegw_list( struct cegw_nlmsg* req, struct cegw_data* d )
+{
+       return 0;
+}
+
+inline static int cegw_flush( struct cegw_nlmsg* req, struct cegw_data* d )
+{
+       req->nh.nlmsg_type  = RTM_DELROUTE;
+       req->rtcan.gwtype = CGW_TYPE_CAN_ETH_UDP;
+       req->rtcan.flags = CEGW_FLUSH; 
+       return 0;
+}
+
 int main( int argc, char* argv[] )
 {
        int s;
-       int src_if = 0, dst_if = 0;
-       int can_ifidx = 0;
        int tmp = 0;
        int cmd = 0;
-       struct in_addr eth_addr;
-       unsigned short eth_port;
-       struct in_addr eth_listen_addr;
-       unsigned short eth_listen_port;
        char* optstr;
        char opt;
        struct sockaddr_nl nladdr;
        int err = 0;
+       struct cegw_nlmsg req;
+       struct cegw_data d;
+       char rxbuf[256];
+       int rsize = 0;
+       struct nlmsghdr* nlh;
+       struct nlmsgerr* rte;
+
+       memset( &d, 0, sizeof(d) );
 
        struct option long_opt[] =
        {
-               { "start-listen", 1, NULL, 'l' },
-               { "stop-listen" , 1, NULL, 'k' },
+               { "add"   , 0, NULL, 'A' },
+               { "flush" , 0, NULL, 'F' },
+               { "list"  , 0, NULL, 'L' },
+               { "listen", 1, NULL, 'l' },
                { 0, 0, 0, 0 }
        };
-       
-       struct {
-               struct nlmsghdr nh;
-               struct rtcanmsg rtcan;
-               char buf[600]; /* enough? */
-       } req;
-       
+
        while( 1 )
        {
                opt = getopt_long( argc, argv, "As:d:", long_opt, NULL );
@@ -133,95 +271,57 @@ int main( int argc, char* argv[] )
 
                switch( opt )
                {
-                       case 's':
-                               cmd |= CMD_ADD_RULE;
-                               if( (optstr = read_iftype( optarg, &src_if )) == NULL )
-                               {
-                                       fprintf( stderr, "error: bad input format\n" );
-                                       goto syntax_error;
-                                       break;
-                               }
-                               
-                               switch( src_if )
-                               {
-                                       case IF_CAN:
-                                               can_ifidx = if_nametoindex( optstr );
-                                               break;
-                                       case IF_ETH_UDP:
-                                               read_addr_port( optstr, &eth_addr, &eth_port );
-                                               break;
-                                       default:
-                                               fprintf( stderr, "error: unrecognized interface" );
-                                               goto syntax_error;
-                                               break;
-                               }
+                       case 'A':
+                               cmd |= CEGW_CMD_ADD;
                                break;
-                       case 'd':
-                               cmd |= CMD_ADD_RULE;
-                               if( (optstr = read_iftype( optarg, &dst_if )) == NULL )
-                               {
-                                       fprintf( stderr, "error: bad input format\n" );
-                                       goto syntax_error;
-                                       break;
-                               }
-                               
-                               switch( dst_if )
-                               {
-                                       case IF_CAN:
-                                               can_ifidx = if_nametoindex( optstr ); /*chk*/
-                                               break;
-                                       case IF_ETH_UDP:
-                                               read_addr_port( optstr, &eth_addr, &eth_port ); /*chk*/
-                                               break;
-                                       default:
-                                               fprintf( stderr, "error: unrecognized interface" );
-                                               break;
-                               }
+                       case 'F':
+                               cmd |= CEGW_CMD_FLUSH;
+                               break;
+                       case 'L':
+                               cmd |= CEGW_CMD_FLUSH;
                                break;
                        case 'l':
-                               cmd |= CMD_START_LISTEN;
+                               cmd |= CEGW_CMD_LISTEN;
                                if( (optstr = read_iftype( optarg, &tmp )) == NULL )
+                               {
+                                       perr( "listen" );
+                                       return -1;
+                               }       
+                               if( tmp != IF_ETH_UDP )
                                {
                                        fprintf( stderr, "error: -l bad input format\n" );
+                                       return -1;
+                               }       
+                               read_addr_port( optstr, &d.eth_listen_addr, &d.eth_listen_port ); /*chk*/
+                               break;
+                       case 's':
+                               if( read_if( optarg, &d.src_if, &d ) != 0 )
+                               {
+                                       fprintf( stderr, "error: bad input format\n" );
                                        goto syntax_error;
                                        break;
                                }
-                               
-                               if( tmp != IF_ETH_UDP )
+                               break;
+                       case 'd':
+                               if( read_if( optarg, &d.dst_if, &d ) != 0 )
                                {
-                                       fprintf( stderr, "error: -l bad input format\n" );
+                                       fprintf( stderr, "error: bad input format\n" );
                                        goto syntax_error;
                                        break;
                                }
-                                       
-                               read_addr_port( optstr, &eth_listen_addr, &eth_listen_port ); /*chk*/
-                       case 'k':
-                               cmd |= CMD_STOP_LISTEN;
                                break;
                        case '?':
+                               fprintf( stderr, "error: unknown option\n" );
+                               return -1;
                                break;
                        default:
                                fprintf( stderr, "error: unknown option\n" );
-                       break;
+                               return -1;
+                               break;
                }                               
        }
 
-       /* 2. do check on arguments */
-       if( cmd & CMD_ADD_RULE )
-       {
-               if( (src_if == 0 || dst_if == 0) || (src_if == dst_if) )
-               {
-                       fprintf( stderr, "error: source or destination not specified\n" );
-                       return -1;
-               }
-       
-               if( src_if == dst_if )
-               {
-                       fprintf( stderr, "error: source and destination same interface type\n" );
-               }
-       }
-       
-       /* 3. prepare netlink message */
+       /* prepare netlink message */
        req.nh.nlmsg_len   = NLMSG_LENGTH( sizeof(struct rtcanmsg) );
        req.nh.nlmsg_type  = RTM_NEWROUTE;
        req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
@@ -231,35 +331,36 @@ int main( int argc, char* argv[] )
        req.rtcan.can_family = AF_CAN;
        req.rtcan.flags = 0;
 
-       if( cmd & CMD_ADD_RULE )
-       {
-               req.rtcan.gwtype = (src_if == IF_CAN) ? CGW_TYPE_CAN_ETH_UDP : CGW_TYPE_ETH_CAN_UDP;
-               addattr_l( &req.nh, sizeof(req), CGW_CAN_IF, &can_ifidx, sizeof(can_ifidx) );
-               switch( req.rtcan.gwtype )
-               {
-                       case CGW_TYPE_CAN_ETH_UDP:
-                               addattr_l( &req.nh, sizeof(req), CGW_ETH_IP, &eth_addr, sizeof(eth_addr) );
-                               addattr_l( &req.nh, sizeof(req), CGW_ETH_PORT, &eth_port, sizeof(eth_port) );
-                               break;
-                       case CGW_TYPE_ETH_CAN_UDP:
-                               break;
-                       default:
-                               break;
-               }
-       }
-       
-       if( cmd & CMD_START_LISTEN )
+       switch( cmd )
        {
-               req.rtcan.gwtype = CGW_TYPE_CONFIG;
-               addattr_l( &req.nh, sizeof(req), CGW_LISTEN_IP, &eth_listen_addr, sizeof(eth_listen_addr) );
-               addattr_l( &req.nh, sizeof(req), CGW_LISTEN_PORT, &eth_listen_port, sizeof(eth_listen_port) );
-               printf( "start listen: %x, %hu\n", eth_listen_addr, eth_listen_port );
+               case 0:
+                       fprintf( stderr, "error: command not specified\n" );
+                       break;
+               case CEGW_CMD_ADD:
+                       if( cegw_add( &req, &d ) != 0 )
+                       {
+                               perr( "add" );
+                               return -1;
+                       }
+                       break;
+               case CEGW_CMD_FLUSH:
+                       cegw_flush( &req, &d );
+                       break;
+               case CEGW_CMD_LIST:
+                       cegw_list( &req, &d );
+                       break;
+               case CEGW_CMD_LISTEN:
+                       cegw_listen( &req, &d );
+                       break;
+               default:
+                       fprintf( stderr, "error: command mismatch\n" );
+                       break;
        }
+
+       /* send over netlink socket */
+       s = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); /* chck */
        
-       /* 4. send over netlink socket */
-       s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); /* chck */
-       
-       memset(&nladdr, 0, sizeof(nladdr));
+       memset( &nladdr, 0, sizeof(nladdr) );
        nladdr.nl_family = AF_NETLINK;
        nladdr.nl_pid    = 0;
        nladdr.nl_groups = 0;
@@ -272,7 +373,23 @@ int main( int argc, char* argv[] )
                return err;
        }
        
-       /* ack? */
+       /* recv */
+       rsize = recv( s, &rxbuf, sizeof(rxbuf), 0 );
+       if( rsize < 0 )
+       {
+               fprintf( stderr, "error: recv\n" );
+               return -1;
+       }
+       nlh = (struct nlmsghdr*)rxbuf;
+       if( nlh->nlmsg_type != NLMSG_ERROR )
+       {
+               fprintf( stderr, "error: unexpected netlink answer\n" );
+               return -1;
+       }
+       rte = (struct nlmsgerr*)NLMSG_DATA( nlh );
+       err = rte->error;
+       if( err < 0 )
+               fprintf( stderr, "error: netlink; %s\n", strerror(abs(err)) );
        
        return 0;
 syntax_error: