From: Radek Matejka Date: Tue, 24 Jul 2012 15:40:11 +0000 (+0200) Subject: kernel/canethgw accepts configuration over netlink X-Git-Url: http://rtime.felk.cvut.cz/gitweb/can-eth-gw.git/commitdiff_plain/e747e7a97c3ae7afdde31d188a5c071b8e282b0b kernel/canethgw accepts configuration over netlink The module accepts routing commands from cegw using netlink. It builds RCU hlist of routing rules and performs routing on received packets on both CAN and UDP. --- diff --git a/kernel/canethgw.c b/kernel/canethgw.c index 6c02f15..0beb89f 100644 --- a/kernel/canethgw.c +++ b/kernel/canethgw.c @@ -21,24 +21,23 @@ static struct socket* udp_sock; static struct socket* can_sock; static struct net_device* can_dev; -struct can_can_gw { - struct can_filter filter; - int src_idx; - int dst_idx; -}; - struct can_eth_gw { - int src_if_index; + int src_if_idx; struct in_addr dst_addr; unsigned short dst_port; + struct hlist_node list; }; struct eth_can_gw { - int dst_if; + int dst_if_idx; + struct hlist_node list; }; +HLIST_HEAD( can_eth_job ); +HLIST_HEAD( eth_can_job ); + struct cegw_setting { struct can_filter filter; @@ -48,27 +47,6 @@ struct cegw_setting unsigned short dst_port; }; -/* list entry for CAN gateways jobs */ -struct cgw_job { - struct hlist_node list; - struct rcu_head rcu; - u32 handled_frames; - u32 dropped_frames; - union { - /* CAN frame data source */ - struct net_device *dev; - } src; - union { - /* CAN frame data destination */ - struct net_device *dev; - } dst; - union { - struct can_can_gw ccgw; - /* tbc */ - }; - u8 gwtype; - u16 flags; -}; /*********************** * UDP ***********************/ @@ -78,6 +56,8 @@ static int gw_udp_recv( void* data ) struct can_frame cf; struct kvec vec; struct msghdr mh; + struct eth_can_gw* job; + struct hlist_node* pos; vec.iov_base = &cf; vec.iov_len = sizeof(cf); @@ -96,21 +76,27 @@ 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 ); - gw_can_send( &cf ); + rcu_read_lock(); + hlist_for_each_entry_rcu( job, pos, ð_can_job, list ) + { + /* ToDo from filter */ + gw_can_send( &cf, job->dst_if_idx ); + } + rcu_read_unlock(); } return 0; } -static void gw_udp_send( struct can_frame* cf ) +inline static void gw_udp_send( struct can_frame* cf, struct in_addr ipaddr, u16 port ) { struct msghdr mh; struct sockaddr_in addr; struct kvec vec; addr.sin_family = AF_INET; - addr.sin_port = htons( 10502 ); - addr.sin_addr.s_addr = 0x0100007f; + addr.sin_port = htons( port ); + addr.sin_addr = ipaddr; mh.msg_name = &addr; mh.msg_namelen = sizeof( addr ); @@ -133,35 +119,50 @@ static int gw_can_recv( void* data ) struct msghdr mh; struct kvec vec; struct can_frame cf; + struct sockaddr_can ca; + struct can_eth_gw* job; + struct hlist_node* pos; - mh.msg_name = NULL; - mh.msg_namelen = 0; + mh.msg_name = &ca; + mh.msg_namelen = sizeof( ca ); mh.msg_control = NULL; mh.msg_controllen = 0; mh.msg_flags = 0; vec.iov_base = &cf; vec.iov_len = sizeof( cf ); - + while( 1 ) { if( kthread_should_stop() ) /**/ break; kernel_recvmsg( can_sock, &mh, &vec, 1, sizeof( cf ), 0 ); - printk( "received can msg_id:%d\n", cf.can_id ); - gw_udp_send( &cf ); + 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 ); + if( job->src_if_idx == ca.can_ifindex ) + gw_udp_send( &cf, job->dst_addr, job->dst_port ); + } + rcu_read_unlock(); } return 0; } -static void gw_can_send( struct can_frame* cf ) +inline static void gw_can_send( struct can_frame* cf, int ifidx ) { struct msghdr mh; - struct kvec vec; + struct kvec vec; + struct sockaddr_can ca = + { + .can_family = AF_CAN, + .can_ifindex = ifidx + }; - mh.msg_name = NULL; - mh.msg_namelen = 0; + mh.msg_name = &ca; + mh.msg_namelen = sizeof( ca ); mh.msg_control = NULL; mh.msg_controllen = 0; mh.msg_flags = 0; @@ -172,7 +173,7 @@ static void gw_can_send( struct can_frame* cf ) kernel_sendmsg( can_sock, &mh, &vec, 1, sizeof( *cf ) ); } -/**/ +/* NetLink */ static int cgw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg ) @@ -180,28 +181,58 @@ 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; if (nlmsg_len(nlh) < sizeof(*r)) return -EINVAL; - + r = nlmsg_data(nlh); if (r->can_family != AF_CAN) return -EPFNOSUPPORT; - /* so far we only support CAN -> CAN routings */ - if (r->gwtype == CGW_TYPE_CAN_ETH_UDP) - printk( KERN_INFO "canethgw: TYPE_CAN_ETH" ); - else - return -1; - err = nlmsg_parse( nlh, sizeof( struct rtcanmsg ), tb, CGW_MAX, NULL ); if( err < 0 ) + { + printk( KERN_ERR "error: nlmsg_parse\n" ); return err; + } - printk( KERN_INFO "can:%d\n", *(u16*)nla_data( tb[CGW_CAN_IF] ) ); - printk( KERN_INFO "eth addr:%x\n", *(u16*)nla_data( tb[CGW_ETH_IP] ) ); - printk( KERN_INFO "eth port:%hu\n", *(u16*)nla_data( tb[CGW_ETH_PORT] ) ); + /* so far we only support CAN -> CAN routings */ + switch( r->gwtype ) + { + 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] ) ); + printk( KERN_INFO "eth port:%hu\n", *(u16*)nla_data( tb[CGW_ETH_PORT] ) ); + cethgw = kmalloc( sizeof(struct can_eth_gw), GFP_KERNEL ); + if( cethgw == NULL ) + { + printk( KERN_ERR "error: kmalloc\n" ); + break; + } + cethgw->src_if_idx = *(int*)nla_data( tb[CGW_CAN_IF] ); + cethgw->dst_addr = *(struct in_addr*)nla_data( tb[CGW_ETH_IP] ); + cethgw->dst_port = *(u16*)nla_data( tb[CGW_ETH_PORT] ); + + hlist_add_head_rcu( &cethgw->list, &can_eth_job ); + break; + case CGW_TYPE_ETH_CAN_UDP: + printk( KERN_INFO "can:%d\n", *(int*)nla_data( tb[CGW_CAN_IF] ) ); + ecangw = kmalloc( sizeof(struct eth_can_gw), GFP_KERNEL ); + if( ecangw == NULL ) + { + printk( KERN_ERR "error: kmalloc\n" ); + break; + } + ecangw->dst_if_idx = *(int*)nla_data( tb[CGW_CAN_IF] ); + hlist_add_head_rcu( &ecangw->list, ð_can_job ); + break; + default: + /* ToDo undef operation */ + break; + } return 0; } @@ -291,3 +322,4 @@ static void __exit cangw_exit( void ) module_init( cangw_init ); module_exit( cangw_exit ); + diff --git a/kernel/canethgw.h b/kernel/canethgw.h index 1ff2edc..5acb34b 100644 --- a/kernel/canethgw.h +++ b/kernel/canethgw.h @@ -1,4 +1,4 @@ static int gw_udp_recv( void* data ); -static void gw_udp_send( struct can_frame* cf ); +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 ); +static void gw_can_send( struct can_frame* cf, int ifidx );