3 #include <linux/module.h>
4 #include <linux/kernel.h>
5 #include <linux/kthread.h>
6 #include <linux/sched.h>
7 #include <linux/delay.h>
8 #include <linux/wait.h>
9 #include <linux/netdevice.h>
10 #include <linux/socket.h>
11 #include <linux/net.h>
12 #include <linux/can/core.h>
13 #include <linux/can.h>
14 #include <net/rtnetlink.h>
17 #include <linux/completion.h>
18 #include <linux/mutex.h>
19 #include <net/inet_common.h>
23 * [ ] encapsule module - check inputs
24 * [ ] refactor - chc .h
26 * [ ] rtnl vs nl functions
28 * [ ] change listening
29 * [ ] clean exit - threads, jobs
32 MODULE_LICENSE( "GPL" );
34 static int cegw_udp_can( void* data );
35 inline static void cegw_udp_send( struct socket* udp_sock, struct can_frame* cf, struct in_addr ipaddr, u16 port );
36 static int cegw_can_udp( void* data );
37 inline static void cegw_can_send( struct socket* can_sock, struct can_frame* cf, int ifindex );
38 static int cegw_thread_start( void );
39 static void cegw_thread_stop( void );
40 static int cegw_thread_restart( void* arg );
42 #define CEGW_STOPPED 0
43 #define CEGW_RUNNING 1
45 static struct socket* can_sock = NULL, * udp_sock = NULL;
46 static struct task_struct* eth_to_can = NULL, * can_to_eth = NULL;
47 /* ToDo: protect with mutex */
48 static int cegw_state = CEGW_STOPPED;
53 struct in_addr eth_ip;
54 unsigned short eth_port;
55 struct hlist_node list;
58 HLIST_HEAD( cegw_rule_can_eth );
59 HLIST_HEAD( cegw_rule_eth_can );
64 struct in_addr eth_addr;
65 unsigned short eth_port;
68 DEFINE_MUTEX( cegw_setting_mutex );
70 inline static void cegw_udp_send( struct socket* udp_sock, struct can_frame* cf, struct in_addr ipaddr, u16 port )
73 struct sockaddr_in addr;
76 addr.sin_family = AF_INET;
77 addr.sin_port = htons( port );
78 addr.sin_addr = ipaddr;
81 mh.msg_namelen = sizeof( addr );
82 mh.msg_control = NULL;
83 mh.msg_controllen = 0;
87 vec.iov_len = sizeof( *cf );
89 kernel_sendmsg( udp_sock, &mh, &vec, 1, sizeof( *cf ) );
92 inline static void cegw_can_send( struct socket* can_sock, struct can_frame* cf, int ifindex )
96 struct sockaddr_can addr;
98 addr.can_family = AF_CAN;
99 addr.can_ifindex = ifindex;
102 mh.msg_namelen = sizeof( addr );
103 mh.msg_control = NULL;
104 mh.msg_controllen = 0;
108 vec.iov_len = sizeof( *cf );
110 kernel_sendmsg( can_sock, &mh, &vec, 1, sizeof( *cf ) ); /* ToDo: handle error */
114 * cegw_udp_can - performs udp->can routing
115 * This function is run as a thread.
117 static int cegw_udp_can( void* data )
122 struct cegw_rule* job;
123 struct hlist_node* pos;
131 mh.msg_control = NULL;
132 mh.msg_controllen = 0;
137 if( cegw_state == CEGW_STOPPED )
140 vec.iov_len = sizeof(cf);
141 recv_size = kernel_recvmsg( udp_sock, &mh, &vec, 1, sizeof(cf), 0 ); /* ToDo: handle error, size check */
146 hlist_for_each_entry_rcu( job, pos, &cegw_rule_eth_can, list )
148 rcu_read_lock(); /**/
149 can_ifidx = job->can_ifindex;
151 /* ToDo: from filter */
152 cegw_can_send( can_sock, &cf, can_ifidx );
160 * cegw_can_udp - performs can->udp routing
162 static int cegw_can_udp( void* data )
167 struct sockaddr_can ca;
168 struct cegw_rule* rule;
169 struct hlist_node* pos;
170 struct in_addr eth_addr;
175 mh.msg_namelen = sizeof( ca );
176 mh.msg_control = NULL;
177 mh.msg_controllen = 0;
182 if( cegw_state == CEGW_STOPPED ) /**/
185 vec.iov_len = sizeof( cf );
187 recv_size = kernel_recvmsg( can_sock, &mh, &vec, 1, sizeof( cf ), 0 );
192 hlist_for_each_entry_rcu( rule, pos, &cegw_rule_can_eth, list )
195 eth_addr = rule->eth_ip;
196 eth_port = rule->eth_port;
198 if( rule->can_ifindex == ca.can_ifindex )
199 cegw_udp_send( udp_sock, &cf, eth_addr, eth_port );
208 static int cegw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg )
210 struct nlattr* tb[ CEGW_MAX+1 ];
211 struct cegw_rule* rule = NULL;
218 if( nlmsg_len(nlh) < sizeof(*r) )
221 r = nlmsg_data( nlh );
223 if( r->rtm_family != AF_CAN )
224 return -EPFNOSUPPORT;
226 err = nlmsg_parse( nlh, sizeof(*r), tb, CEGW_MAX, NULL );
229 pr_devel( "canethgw: nlmsg_parse error\n" );
233 if( tb[CEGW_CMD_INFO] == NULL )
235 pr_devel( "canethgw: CEGW_CMD_INFO is missing in rtmsg\n" );
239 switch( *(int*)nla_data( tb[CEGW_CMD_INFO] ) )
242 if( !tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] )
244 pr_devel( "canethgw: missing attribute for CEGW_LISTEN\n" );
248 mutex_lock( &cegw_setting_mutex );
249 cegw_setting.eth_addr = *(struct in_addr*)nla_data( tb[CEGW_ETH_IP] );
250 cegw_setting.eth_port = *(unsigned short*)nla_data( tb[CEGW_ETH_PORT] );
251 kthread_run( cegw_thread_restart, NULL, "canethgw" );
252 mutex_unlock( &cegw_setting_mutex );
254 case CEGW_RULE_CAN_ETH:
255 if( !tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] || !tb[CEGW_CAN_IFINDEX] )
257 pr_devel( "canethgw: missing attribute for CEGW_RULE_CAN_ETH\n" );
261 ifindex = *(int*)nla_data( tb[CEGW_CAN_IFINDEX] );
262 ip = *(struct in_addr*)nla_data( tb[CEGW_ETH_IP] );
263 port = *(unsigned short*)nla_data( tb[CEGW_ETH_PORT] );
264 pr_devel( "canethgw: new can->eth rule - (%d)->(%x:%hu)\n", ifindex, ip.s_addr, port );
266 rule = kmalloc( sizeof(struct cegw_rule), GFP_KERNEL );
272 rule->can_ifindex = ifindex;
274 rule->eth_port = port;
276 hlist_add_head_rcu( &rule->list, &cegw_rule_can_eth );
278 case CEGW_RULE_ETH_CAN:
279 if( !tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] || !tb[CEGW_CAN_IFINDEX] )
281 pr_devel( "canethgw: missing attribute for CEGW_RULE_ETH_CAN\n" );
285 ifindex = *(int*)nla_data( tb[CEGW_CAN_IFINDEX] );
286 ip = *(struct in_addr*)nla_data( tb[CEGW_ETH_IP] );
287 port = *(unsigned short*)nla_data( tb[CEGW_ETH_PORT] );
288 pr_devel( "canethgw: new eth->can rule - (%x:%hu)->(%d)\n", ip.s_addr, port, ifindex );
290 rule = kmalloc( sizeof(struct cegw_rule), GFP_KERNEL );
296 rule->can_ifindex = ifindex;
298 rule->eth_port = port;
300 hlist_add_head_rcu( &rule->list, &cegw_rule_eth_can );
303 pr_devel( "canethgw: unknown CEGW_CMD_INFO\n" );
310 static int cegw_remove_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg )
313 struct nlattr* tb[ CEGW_MAX+1 ];
314 struct hlist_node* pos,* n;
315 struct cegw_rule* rule;
319 if( nlmsg_len(nlh) < sizeof(*r) )
322 r = nlmsg_data( nlh );
324 if( r->rtm_family != AF_CAN )
325 return -EPFNOSUPPORT;
327 err = nlmsg_parse( nlh, sizeof(struct rtmsg), tb, CEGW_MAX, NULL );
331 if( tb[CEGW_CMD_INFO] == NULL )
333 pr_devel( "canethgw: CEGW_CMD_INFO is missing in rtmsg\n" );
337 if( *(int*)nla_data( tb[CEGW_CMD_INFO] ) != CEGW_FLUSH )
342 hlist_for_each_entry_safe( rule, pos, n, &cegw_rule_can_eth, list )
344 hlist_del( &rule->list );
347 hlist_for_each_entry_safe( rule, pos, n, &cegw_rule_eth_can, list )
349 hlist_del( &rule->list );
356 static int cegw_put_rule( struct sk_buff* skb, int type, struct cegw_rule* rule )
361 struct nlmsghdr* nlh;
363 ifindex = rule->can_ifindex;
365 port = rule->eth_port;
367 nlh = nlmsg_put( skb, 0, 0, 0, 0, 0 );
372 if( nla_put( skb, CEGW_TYPE, sizeof(type), &type ) < 0 )
375 nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(type) );
378 if( nla_put( skb, CEGW_CAN_IFINDEX, sizeof(ifindex), &ifindex ) < 0 )
381 nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(ifindex) );
384 if( nla_put( skb, CEGW_ETH_IP, sizeof(ip), &ip) < 0 )
387 nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(ip) );
390 if( nla_put( skb, CEGW_ETH_PORT, sizeof(port), &port ) < 0 )
393 nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(port) );
398 nlmsg_cancel( skb, nlh );
402 static int cegw_dump_job( struct sk_buff* skb, struct netlink_callback* cb )
404 struct cegw_rule* rule;
405 struct hlist_node* pos;
407 int s_idx = cb->args[0];
409 /* ToDo: skb max size */
412 hlist_for_each_entry_rcu( rule, pos, &cegw_rule_eth_can, list )
417 if( cegw_put_rule( skb, CEGW_RULE_ETH_CAN, rule ) < 0 )
425 hlist_for_each_entry_rcu( rule, pos, &cegw_rule_can_eth, list )
430 if( cegw_put_rule( skb, CEGW_RULE_CAN_ETH, rule ) < 0 )
444 static int cegw_thread_start( void )
446 struct sockaddr_in udp_addr;
447 struct sockaddr_can can_addr;
449 can_addr.can_family = AF_CAN;
450 can_addr.can_ifindex = 0;
452 udp_addr.sin_family = AF_INET;
453 udp_addr.sin_port = htons( cegw_setting.eth_port );
454 udp_addr.sin_addr = cegw_setting.eth_addr;
456 /* create and bind sockets */
457 if( sock_create_kern( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &udp_sock) != 0 )
459 printk( KERN_ERR "canethgw: udp socket creation failed\n" );
463 if( sock_create_kern( PF_CAN, SOCK_RAW, CAN_RAW, &can_sock) != 0 )
465 printk( KERN_ERR "canethgw: can socket creation failed\n" );
469 if( kernel_bind( udp_sock, (struct sockaddr*)&udp_addr, sizeof( udp_addr ) ) != 0 )
471 printk( KERN_ERR "canethgw: udp socket binding failed\n" );
472 sock_release( udp_sock );
473 sock_release( can_sock );
474 return -1; /* ToDo: state==RUNNING and return? */
477 if( kernel_bind( can_sock, (struct sockaddr*) &can_addr, sizeof(can_addr) ) != 0 )
479 printk( KERN_ERR "canethgw: can socket binding failed\n" );
480 sock_release( udp_sock );
481 sock_release( can_sock );
486 cegw_state = CEGW_RUNNING;
487 eth_to_can = kthread_create( cegw_udp_can, NULL, "canethgw" );
488 if( !IS_ERR( eth_to_can ) )
490 get_task_struct( eth_to_can );
491 wake_up_process( eth_to_can );
493 can_to_eth = kthread_create( cegw_can_udp, NULL, "canethgw" );
494 if( !IS_ERR( can_to_eth ) )
496 /* ToDo: free this? */
497 get_task_struct( can_to_eth );
498 wake_up_process( can_to_eth );
501 /* ToDo: kthread creation fail */
502 pr_devel( "threads are running\n" );
507 static void cegw_thread_stop( void )
510 struct sock* sk = NULL;
512 /* no threads are running */
513 if( !can_to_eth && !eth_to_can )
516 cegw_state = CEGW_STOPPED;
517 /* shut down socket */
521 sk->sk_shutdown |= how;
522 sk->sk_state_change( sk );
525 kernel_sock_shutdown( udp_sock, SHUT_RDWR );
527 /* wait for return to reuse port if restart */
528 kthread_stop( eth_to_can );
529 kthread_stop( can_to_eth );
530 sock_release( udp_sock );
531 sock_release( can_sock );
537 * cegw_thread_restart
539 static int cegw_thread_restart( void* data )
547 /***********************
549 ***********************/
551 static int __init cegw_init( void )
553 /* subscribe to netlink */
554 rtnl_register( PF_CAN, RTM_GETROUTE, NULL, cegw_dump_job, NULL );
555 rtnl_register( PF_CAN, RTM_NEWROUTE, cegw_create_job, NULL, NULL );
556 rtnl_register( PF_CAN, RTM_DELROUTE, cegw_remove_job, NULL, NULL );
561 static void __exit cegw_exit( void )
563 /* ToDo: effect on others? */
564 rtnl_unregister_all( PF_CAN );
566 /* ToDo: no rtnl pending? */
568 /* ToDo: frees mem_cache? */
569 /* udp must not exists */
571 printk( "cangw: exit\n" );
574 module_init( cegw_init );
575 module_exit( cegw_exit );