From a5d61b569fe49e2ca9f8f38f0af5a0b147f2b806 Mon Sep 17 00:00:00 2001 From: Radek Matejka Date: Wed, 25 Jul 2012 19:16:50 +0200 Subject: [PATCH] set udp listening address --- kernel/Makefile | 6 +- kernel/canethgw.c | 141 +++++++++++++++++++++------------ kernel/canethgw.h | 52 +++++++++++- utils/{cangw => cegw}/Makefile | 0 utils/{cangw => cegw}/cegw.c | 99 +++++++++++++++++------ 5 files changed, 213 insertions(+), 85 deletions(-) rename utils/{cangw => cegw}/Makefile (100%) rename utils/{cangw => cegw}/cegw.c (69%) diff --git a/kernel/Makefile b/kernel/Makefile index b7a37f6..b9ba2f5 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,11 +1,11 @@ obj-m += canethgw.o all: - make -C /lib/modules/`uname -r`/build M=`pwd` + make -C /usr/src/linux/_build_qemu M=`pwd` install: - make -C /lib/modules/`uname -r`/build M=`pwd` modules_install + make -C /usr/src/linux/_build_qemu M=`pwd` modules_install clean: - make -C /lib/modules/`uname -r`/build M=`pwd` clean + make -C /usr/src/linux/_build_qemu M=`pwd` clean test: modprobe -r canethgw modprobe canethgw diff --git a/kernel/canethgw.c b/kernel/canethgw.c index 0beb89f..992ded9 100644 --- a/kernel/canethgw.c +++ b/kernel/canethgw.c @@ -1,5 +1,3 @@ -#include "gw.h" /* override */ - #include #include #include @@ -14,12 +12,27 @@ #include #include "canethgw.h" +/** + * ToDo + * [ ] check every input + * [ ] refactor + */ + MODULE_LICENSE( "GPL" ); +static int gw_udp_recv( void* data ); +static void gw_udp_send( struct can_frame* cf, struct in_addr ipaddr, u16 port ); +static int gw_can_recv( void* data ); +static void gw_can_send( struct can_frame* cf, int ifidx ); +static int listen( int can_ifidx, struct in_addr eth_addr, u16 eth_port ); + +#define CEGW_STOPPED 0 +#define CEGW_RUNNING 1 + static struct task_struct* eth_to_can, * can_to_eth; -static struct socket* udp_sock; -static struct socket* can_sock; -static struct net_device* can_dev; +static struct socket* udp_sock = NULL; +static struct socket* can_sock = NULL; +static int gw_state = CEGW_STOPPED; struct can_eth_gw { @@ -58,6 +71,7 @@ static int gw_udp_recv( void* data ) struct msghdr mh; struct eth_can_gw* job; struct hlist_node* pos; + int can_ifidx; vec.iov_base = &cf; vec.iov_len = sizeof(cf); @@ -76,13 +90,14 @@ static int gw_udp_recv( void* data ) break; kernel_recvmsg( udp_sock, &mh, &vec, 1, sizeof(cf), 0 ); /* todo: handle error */ printk( "received udp msg_id:%d\n", cf.can_id ); - rcu_read_lock(); hlist_for_each_entry_rcu( job, pos, ð_can_job, list ) { + rcu_read_lock(); /**/ + can_ifidx = job->dst_if_idx; + rcu_read_unlock(); /* ToDo from filter */ - gw_can_send( &cf, job->dst_if_idx ); + gw_can_send( &cf, can_ifidx ); } - rcu_read_unlock(); } return 0; @@ -122,6 +137,8 @@ static int gw_can_recv( void* data ) struct sockaddr_can ca; struct can_eth_gw* job; struct hlist_node* pos; + struct in_addr eth_addr; + u16 eth_port; mh.msg_name = &ca; mh.msg_namelen = sizeof( ca ); @@ -138,14 +155,16 @@ static int gw_can_recv( void* data ) break; kernel_recvmsg( can_sock, &mh, &vec, 1, sizeof( cf ), 0 ); printk( "received can msg_id:%d, from:%d\n", cf.can_id, ca.can_ifindex ); - rcu_read_lock(); hlist_for_each_entry_rcu( job, pos, &can_eth_job, list ) { - printk( KERN_INFO "%x\n", job->dst_addr ); + rcu_read_lock(); + eth_addr = job->dst_addr; + eth_port = job->dst_port; + rcu_read_unlock(); + printk( KERN_INFO "%x\n", eth_addr ); if( job->src_if_idx == ca.can_ifindex ) - gw_udp_send( &cf, job->dst_addr, job->dst_port ); + gw_udp_send( &cf, eth_addr, eth_port ); } - rcu_read_unlock(); } return 0; @@ -180,7 +199,6 @@ static int cgw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, { struct nlattr* tb[ CGW_MAX+1 ]; struct rtcanmsg *r; - struct cgw_job *gwj; struct can_eth_gw* cethgw = NULL; struct eth_can_gw* ecangw = NULL; int err = 0; @@ -199,9 +217,12 @@ static int cgw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, return err; } - /* so far we only support CAN -> CAN routings */ switch( r->gwtype ) { + case CGW_TYPE_CONFIG: + listen( 0, *(struct in_addr*)nla_data( tb[CGW_LISTEN_IP] ), + *(u16*)nla_data( tb[CGW_LISTEN_PORT] ) ); + break; case CGW_TYPE_CAN_ETH_UDP: printk( KERN_INFO "can:%d\n", *(int*)nla_data( tb[CGW_CAN_IF] ) ); printk( KERN_INFO "eth addr:%x\n", *(u32*)nla_data( tb[CGW_ETH_IP] ) ); @@ -230,6 +251,7 @@ static int cgw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, hlist_add_head_rcu( &ecangw->list, ð_can_job ); break; default: + printk( "default" ); /* ToDo undef operation */ break; } @@ -237,34 +259,22 @@ static int cgw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, return 0; } -/*********************** - * module init/exit - ***********************/ - -static int __init cangw_init( void ) -{ +static int listen( int can_ifidx, struct in_addr eth_addr, u16 eth_port ) +{ struct sockaddr_in udp_addr; struct sockaddr_can can_addr; - int ifidx = 0; - - /* 1. create can socket and bind to it */ - can_dev = dev_get_by_name( &init_net, "vcan0" ); /* net ns?, release counter! */ - if( can_dev == NULL ) - { - printk( KERN_ERR "error: vcan0 not found\n" ); - return -1; - } - ifidx = can_dev->ifindex; - dev_put( can_dev ); - - if( sock_create_kern( PF_CAN, SOCK_RAW, CAN_RAW, &can_sock) != 0 ) + struct socket* tmp; + + printk( KERN_INFO "listen called\n" ); + + if( sock_create_kern( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &tmp) != 0 ) { printk( KERN_ERR "error: can_sock creation failed\n" ); return -1; } - + can_addr.can_family = AF_CAN; - can_addr.can_ifindex = ifidx; + can_addr.can_ifindex = can_ifidx; if( can_sock->ops->bind( can_sock, (struct sockaddr*) &can_addr, sizeof(can_addr) ) != 0 ) { @@ -272,35 +282,58 @@ static int __init cangw_init( void ) return -1; } - /* 2. create udp socket and bind to it */ - if( sock_create_kern( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &udp_sock ) != 0 ) + printk( KERN_INFO "can socket success\n" ); + + udp_addr.sin_family = AF_INET; + udp_addr.sin_port = htons( eth_port ); + udp_addr.sin_addr = eth_addr; + + printk( KERN_INFO "trying to bind\n" ); + if( udp_sock->ops->bind( udp_sock, (struct sockaddr*)&udp_addr, sizeof( udp_addr ) ) != 0 ) /* ref impl ?!? */ { - printk( "error: udp_sock creation failed\n" ); + printk( "error: binding failed\n" ); + sock_release( udp_sock ); sock_release( can_sock ); return -1; } + + printk( KERN_INFO "socket established\n" ); - udp_addr.sin_family = AF_INET; - udp_addr.sin_port = htons( 10501 ); - udp_addr.sin_addr.s_addr = INADDR_ANY; + /* run threads */ + eth_to_can = kthread_run( gw_udp_recv, NULL, "ethcangw" ); + can_to_eth = kthread_run( gw_can_recv, NULL, "canethgw" ); - if( udp_sock->ops->bind( udp_sock, (struct sockaddr*)&udp_addr, sizeof( udp_addr ) ) != 0 ) /* ref impl ?!? */ + printk( KERN_INFO "threads are running\n" ); + + gw_state = CEGW_RUNNING; + + return 0; +} + +/*********************** + * module init/exit + ***********************/ + +static int __init cangw_init( void ) +{ + if( sock_create_kern( PF_CAN, SOCK_RAW, CAN_RAW, &can_sock) != 0 ) { - printk( "error: binding failed\n" ); - sock_release( udp_sock ); + printk( KERN_ERR "error: can_sock creation failed\n" ); + return -1; + } + + if( sock_create_kern( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &udp_sock ) != 0 ) + { + printk( KERN_ERR "error: udp_sock creation failed\n" ); sock_release( can_sock ); return -1; } - /* 3. subscribe to netlink */ + /* 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_DELROUTE, ) - /* 4. run threads */ - eth_to_can = kthread_run( gw_udp_recv, NULL, "cangw" ); - can_to_eth = kthread_run( gw_can_recv, NULL, "cangw" ); - /* if( sock_create_kern( AF_CAN, SOCK_RAW, CAN_RAW, &can_sock ) != 0 ) {s @@ -313,9 +346,13 @@ static int __init cangw_init( void ) static void __exit cangw_exit( void ) { - sock_release( udp_sock ); - sock_release( can_sock ); - + if( gw_state == CEGW_RUNNING ) + { + sock_release( udp_sock ); + sock_release( can_sock ); + /* ToDo: stop threads */ + } + printk( "cangw: exit\n" ); //kthread_stop( ts ); } diff --git a/kernel/canethgw.h b/kernel/canethgw.h index 5acb34b..f09a420 100644 --- a/kernel/canethgw.h +++ b/kernel/canethgw.h @@ -1,4 +1,48 @@ -static int gw_udp_recv( void* data ); -static void gw_udp_send( struct can_frame* cf, struct in_addr ipaddr, u16 port ); -static int gw_can_recv( void* data ); -static void gw_can_send( struct can_frame* cf, int ifidx ); +#ifndef CANETHGW_H +#define CANETHGW_H + +#include +#include + +/* these are from gw.h */ +struct rtcanmsg { + __u8 can_family; + __u8 gwtype; + __u16 flags; +}; + +enum { + CGW_TYPE_UNSPEC, + CGW_TYPE_CAN_CAN, /* CAN->CAN routing */ + CGW_TYPE_CAN_ETH_UDP, /* CAN->ETH udp */ + CGW_TYPE_ETH_CAN_UDP, /* ETH->CAN udp */ + CGW_TYPE_CAN_ETH_TCP, + CGW_TYPE_CONFIG, + __CGW_TYPE_MAX +}; + +#define CGW_TYPE_MAX (__CGW_TYPE_MAX - 1) + +enum { + CGW_UNSPEC, + CGW_MOD_AND, /* CAN frame modification binary AND */ + CGW_MOD_OR, /* CAN frame modification binary OR */ + CGW_MOD_XOR, /* CAN frame modification binary XOR */ + CGW_MOD_SET, /* CAN frame modification set alternate values */ + CGW_CS_XOR, /* set data[] XOR checksum into data[index] */ + CGW_CS_CRC8, /* set data[] CRC8 checksum into data[index] */ + CGW_HANDLED, /* number of handled CAN frames */ + CGW_DROPPED, /* number of dropped CAN frames */ + CGW_CAN_IF, /* ifindex of source network interface */ + CGW_LISTEN_IP, + CGW_LISTEN_PORT, + CGW_ETH_IP, + CGW_ETH_PORT, + CGW_ETH_PROTO, /* ifindex of destination network interface */ + CGW_FILTER, /* specify struct can_filter on source CAN device */ + __CGW_MAX +}; + +#define CGW_MAX (__CGW_MAX - 1) +#endif /* CANETHGW_H */ + diff --git a/utils/cangw/Makefile b/utils/cegw/Makefile similarity index 100% rename from utils/cangw/Makefile rename to utils/cegw/Makefile diff --git a/utils/cangw/cegw.c b/utils/cegw/cegw.c similarity index 69% rename from utils/cangw/cegw.c rename to utils/cegw/cegw.c index 5233627..275d659 100644 --- a/utils/cangw/cegw.c +++ b/utils/cegw/cegw.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include #include @@ -10,12 +10,22 @@ #include #include #include -#include +#include +#include +#include "canethgw.h" /** * ToDo - * - refactor error messages - * */ + * [ ] refactor error messages + * [ ] start/stop listening + * [ ] remove routing job + * [ ] recv netlink reponse + * + */ + +#define CMD_STOP_LISTEN 1 +#define CMD_START_LISTEN 2 +#define CMD_ADD_RULE 4 enum { IF_UNDEF, @@ -23,6 +33,15 @@ enum { IF_ETH_UDP }; + +/** + * 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 + * @return 0 on success + */ int read_addr_port( char* in, struct in_addr* addr, unsigned short* port ) { char* delim = NULL; @@ -83,7 +102,7 @@ int main( int argc, char* argv[] ) int src_if = 0, dst_if = 0; int can_ifidx = 0; int tmp = 0; - int have_listen = 0; + int cmd = 0; struct in_addr eth_addr; unsigned short eth_port; struct in_addr eth_listen_addr; @@ -92,6 +111,13 @@ int main( int argc, char* argv[] ) char opt; struct sockaddr_nl nladdr; int err = 0; + + struct option long_opt[] = + { + { "start-listen", 1, NULL, 'l' }, + { "stop-listen" , 1, NULL, 'k' }, + { 0, 0, 0, 0 } + }; struct { struct nlmsghdr nh; @@ -99,11 +125,16 @@ int main( int argc, char* argv[] ) char buf[600]; /* enough? */ } req; - while( (opt = getopt( argc, argv, "As:d:l:" )) != -1 ) + while( 1 ) { + opt = getopt_long( argc, argv, "As:d:", long_opt, NULL ); + if( opt == -1 ) + break; + switch( opt ) { case 's': + cmd |= CMD_ADD_RULE; if( (optstr = read_iftype( optarg, &src_if )) == NULL ) { fprintf( stderr, "error: bad input format\n" ); @@ -126,6 +157,7 @@ int main( int argc, char* argv[] ) } break; case 'd': + cmd |= CMD_ADD_RULE; if( (optstr = read_iftype( optarg, &dst_if )) == NULL ) { fprintf( stderr, "error: bad input format\n" ); @@ -147,6 +179,7 @@ int main( int argc, char* argv[] ) } break; case 'l': + cmd |= CMD_START_LISTEN; if( (optstr = read_iftype( optarg, &tmp )) == NULL ) { fprintf( stderr, "error: -l bad input format\n" ); @@ -162,6 +195,11 @@ int main( int argc, char* argv[] ) } read_addr_port( optstr, ð_listen_addr, ð_listen_port ); /*chk*/ + case 'k': + cmd |= CMD_STOP_LISTEN; + break; + case '?': + break; default: fprintf( stderr, "error: unknown option\n" ); break; @@ -169,15 +207,18 @@ int main( int argc, char* argv[] ) } /* 2. do check on arguments */ - if( (src_if == 0 || dst_if == 0) || (src_if == dst_if) ) + if( cmd & CMD_ADD_RULE ) { - fprintf( stderr, "error: source or destination not specified\n" ); - return -1; - } + 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" ); + if( src_if == dst_if ) + { + fprintf( stderr, "error: source and destination same interface type\n" ); + } } /* 3. prepare netlink message */ @@ -188,26 +229,31 @@ int main( int argc, char* argv[] ) req.nh.nlmsg_pid = 0; /* ? */ req.rtcan.can_family = AF_CAN; - req.rtcan.gwtype = (src_if == IF_CAN) ? CGW_TYPE_CAN_ETH_UDP : CGW_TYPE_ETH_CAN_UDP; req.rtcan.flags = 0; - - addattr_l( &req.nh, sizeof(req), CGW_CAN_IF, &can_ifidx, sizeof(can_ifidx) ); - switch( req.rtcan.gwtype ) + + if( cmd & CMD_ADD_RULE ) { - 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; + 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( have_listen ) + if( cmd & CMD_START_LISTEN ) { + 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 ); } /* 4. send over netlink socket */ @@ -232,3 +278,4 @@ int main( int argc, char* argv[] ) syntax_error: return -1; } + -- 2.39.2