From: Radek Matejka Date: Thu, 26 Jul 2012 16:10:45 +0000 (+0200) Subject: cegw refactor X-Git-Url: https://rtime.felk.cvut.cz/gitweb/can-eth-gw.git/commitdiff_plain/b9d3942507f010fc6af5e961199cbc6778f8b1c7 cegw refactor --- diff --git a/kernel/canethgw.c b/kernel/canethgw.c index 992ded9..88f2614 100644 --- a/kernel/canethgw.c +++ b/kernel/canethgw.c @@ -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 ); } diff --git a/kernel/canethgw.h b/kernel/canethgw.h index f09a420..cfcd1b6 100644 --- a/kernel/canethgw.h +++ b/kernel/canethgw.h @@ -21,6 +21,10 @@ enum { __CGW_TYPE_MAX }; +enum { + CEGW_FLUSH +}; + #define CGW_TYPE_MAX (__CGW_TYPE_MAX - 1) enum { diff --git a/utils/cegw/cegw.c b/utils/cegw/cegw.c index 275d659..efbe2c7 100644 --- a/utils/cegw/cegw.c +++ b/utils/cegw/cegw.c @@ -23,20 +23,69 @@ * */ -#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, ð_addr, ð_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, ð_addr, ð_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, ð_listen_addr, ð_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, ð_addr, sizeof(eth_addr) ); - addattr_l( &req.nh, sizeof(req), CGW_ETH_PORT, ð_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, ð_listen_addr, sizeof(eth_listen_addr) ); - addattr_l( &req.nh, sizeof(req), CGW_LISTEN_PORT, ð_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: