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>
21 MODULE_LICENSE( "GPL" );
23 static int cegw_udp_can( void* data );
24 inline static void cegw_udp_send( struct socket* udp_sock, struct can_frame* cf, struct in_addr ipaddr, u16 port );
25 static int cegw_can_udp( void* data );
26 inline static void cegw_can_send( struct socket* can_sock, struct can_frame* cf, int ifindex );
27 static int cegw_thread_start( void* data );
28 static int cegw_thread_stop( void );
40 struct in_addr eth_ip;
41 unsigned short eth_port;
42 struct hlist_node list;
47 struct in_addr eth_ip;
48 unsigned short eth_port;
51 static int cegw_state = CEGW_STOP;
52 static struct socket* can_sock = NULL, * udp_sock = NULL;
53 static struct task_struct* eth_to_can = NULL, * can_to_eth = NULL;
55 HLIST_HEAD( cegw_rule_can_eth );
56 HLIST_HEAD( cegw_rule_eth_can );
57 DEFINE_MUTEX( cegw_mutex );
59 inline static void cegw_udp_send( struct socket* udp_sock, struct can_frame* cf, struct in_addr ipaddr, u16 port )
62 struct sockaddr_in addr;
65 addr.sin_family = AF_INET;
66 addr.sin_port = htons( port );
67 addr.sin_addr = ipaddr;
70 mh.msg_namelen = sizeof( addr );
71 mh.msg_control = NULL;
72 mh.msg_controllen = 0;
76 vec.iov_len = sizeof( *cf );
78 kernel_sendmsg( udp_sock, &mh, &vec, 1, sizeof( *cf ) );
81 inline static void cegw_can_send( struct socket* can_sock, struct can_frame* cf, int ifindex )
85 struct sockaddr_can addr;
87 addr.can_family = AF_CAN;
88 addr.can_ifindex = ifindex;
91 mh.msg_namelen = sizeof( addr );
92 mh.msg_control = NULL;
93 mh.msg_controllen = 0;
97 vec.iov_len = sizeof( *cf );
99 kernel_sendmsg( can_sock, &mh, &vec, 1, sizeof( *cf ) ); /* ToDo: handle error */
103 * cegw_udp_can - performs udp->can routing
104 * This function is run as a thread.
106 static int cegw_udp_can( void* data )
111 struct cegw_rule* job;
112 struct hlist_node* pos;
120 mh.msg_control = NULL;
121 mh.msg_controllen = 0;
126 if( cegw_state == CEGW_STOP )
129 vec.iov_len = sizeof(cf);
130 recv_size = kernel_recvmsg( udp_sock, &mh, &vec, 1, sizeof(cf), 0 ); /* ToDo: handle error, size check */
135 hlist_for_each_entry_rcu( job, pos, &cegw_rule_eth_can, list )
137 rcu_read_lock(); /**/
138 can_ifidx = job->can_ifindex;
140 /* ToDo: from filter */
141 cegw_can_send( can_sock, &cf, can_ifidx );
149 * cegw_can_udp - performs can->udp routing
151 static int cegw_can_udp( void* data )
156 struct sockaddr_can ca;
157 struct cegw_rule* rule;
158 struct hlist_node* pos;
159 struct in_addr eth_ip;
164 mh.msg_namelen = sizeof( ca );
165 mh.msg_control = NULL;
166 mh.msg_controllen = 0;
171 if( cegw_state == CEGW_STOP ) /**/
174 vec.iov_len = sizeof( cf );
176 recv_size = kernel_recvmsg( can_sock, &mh, &vec, 1, sizeof( cf ), 0 );
181 hlist_for_each_entry_rcu( rule, pos, &cegw_rule_can_eth, list )
184 eth_ip = rule->eth_ip;
185 eth_port = rule->eth_port;
187 if( rule->can_ifindex == ca.can_ifindex )
188 cegw_udp_send( udp_sock, &cf, eth_ip, eth_port );
197 static int cegw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg )
199 struct nlattr* tb[ CEGW_MAX+1 ];
200 struct cegw_rule* rule = NULL;
205 struct cegw_setting* set;
208 if( nlmsg_len(nlh) < sizeof(*r) )
211 r = nlmsg_data( nlh );
213 if( r->rtm_family != AF_CAN )
214 return -EPFNOSUPPORT;
216 err = nlmsg_parse( nlh, sizeof(*r), tb, CEGW_MAX, NULL );
219 pr_devel( "canethgw: nlmsg_parse error\n" );
223 if( tb[CEGW_CMD_INFO] == NULL )
225 pr_devel( "canethgw: CEGW_CMD_INFO is missing in rtmsg\n" );
229 switch( *(int*)nla_data( tb[CEGW_CMD_INFO] ) )
232 if( !tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] )
234 pr_devel( "canethgw: missing attribute for CEGW_LISTEN\n" );
238 /* ToDo: valid listen address */
239 set = kmalloc( sizeof(*set), GFP_KERNEL );
240 set->eth_ip = *(struct in_addr*)nla_data( tb[CEGW_ETH_IP] );
241 set->eth_port = *(unsigned short*)nla_data( tb[CEGW_ETH_PORT] );
242 kthread_run( cegw_thread_start, set, "canethgw" );
244 case CEGW_RULE_CAN_ETH:
245 if( !tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] || !tb[CEGW_CAN_IFINDEX] )
247 pr_devel( "canethgw: missing attribute for CEGW_RULE_CAN_ETH\n" );
251 ifindex = *(int*)nla_data( tb[CEGW_CAN_IFINDEX] );
252 ip = *(struct in_addr*)nla_data( tb[CEGW_ETH_IP] );
253 port = *(unsigned short*)nla_data( tb[CEGW_ETH_PORT] );
254 pr_devel( "canethgw: new can->eth rule - (%d)->(%x:%hu)\n", ifindex, ip.s_addr, port );
256 rule = kmalloc( sizeof(struct cegw_rule), GFP_KERNEL );
262 rule->can_ifindex = ifindex;
264 rule->eth_port = port;
266 hlist_add_head_rcu( &rule->list, &cegw_rule_can_eth );
268 case CEGW_RULE_ETH_CAN:
269 if( !tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] || !tb[CEGW_CAN_IFINDEX] )
271 pr_devel( "canethgw: missing attribute for CEGW_RULE_ETH_CAN\n" );
275 ifindex = *(int*)nla_data( tb[CEGW_CAN_IFINDEX] );
276 ip = *(struct in_addr*)nla_data( tb[CEGW_ETH_IP] );
277 port = *(unsigned short*)nla_data( tb[CEGW_ETH_PORT] );
278 pr_devel( "canethgw: new eth->can rule - (%x:%hu)->(%d)\n", ip.s_addr, port, ifindex );
280 rule = kmalloc( sizeof(struct cegw_rule), GFP_KERNEL );
286 rule->can_ifindex = ifindex;
288 rule->eth_port = port;
290 hlist_add_head_rcu( &rule->list, &cegw_rule_eth_can );
293 pr_devel( "canethgw: unknown CEGW_CMD_INFO\n" );
300 static void cegw_flush( void )
302 struct hlist_node* pos,* n;
303 struct cegw_rule* rule;
305 hlist_for_each_entry_safe( rule, pos, n, &cegw_rule_can_eth, list )
307 hlist_del( &rule->list );
310 hlist_for_each_entry_safe( rule, pos, n, &cegw_rule_eth_can, list )
312 hlist_del( &rule->list );
317 static int cegw_remove_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg )
320 struct nlattr* tb[ CEGW_MAX+1 ];
323 if( nlmsg_len(nlh) < sizeof(*r) )
326 r = nlmsg_data( nlh );
328 if( r->rtm_family != AF_CAN )
329 return -EPFNOSUPPORT;
331 err = nlmsg_parse( nlh, sizeof(struct rtmsg), tb, CEGW_MAX, NULL );
335 if( tb[CEGW_CMD_INFO] == NULL )
337 pr_devel( "canethgw: CEGW_CMD_INFO is missing in rtmsg\n" );
341 if( *(int*)nla_data( tb[CEGW_CMD_INFO] ) != CEGW_FLUSH )
351 static int cegw_put_rule( struct sk_buff* skb, int type, struct cegw_rule* rule )
356 struct nlmsghdr* nlh;
358 ifindex = rule->can_ifindex;
360 port = rule->eth_port;
362 nlh = nlmsg_put( skb, 0, 0, 0, 0, 0 );
367 if( nla_put( skb, CEGW_TYPE, sizeof(type), &type ) < 0 )
370 nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(type) );
373 if( nla_put( skb, CEGW_CAN_IFINDEX, sizeof(ifindex), &ifindex ) < 0 )
376 nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(ifindex) );
379 if( nla_put( skb, CEGW_ETH_IP, sizeof(ip), &ip) < 0 )
382 nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(ip) );
385 if( nla_put( skb, CEGW_ETH_PORT, sizeof(port), &port ) < 0 )
388 nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(port) );
393 nlmsg_cancel( skb, nlh );
397 static int cegw_dump_job( struct sk_buff* skb, struct netlink_callback* cb )
399 struct cegw_rule* rule;
400 struct hlist_node* pos;
402 int s_idx = cb->args[0];
404 /* ToDo: skb max size */
407 hlist_for_each_entry_rcu( rule, pos, &cegw_rule_eth_can, list )
412 if( cegw_put_rule( skb, CEGW_RULE_ETH_CAN, rule ) < 0 )
420 hlist_for_each_entry_rcu( rule, pos, &cegw_rule_can_eth, list )
425 if( cegw_put_rule( skb, CEGW_RULE_CAN_ETH, rule ) < 0 )
440 * cegw_thread_start - start working threads
441 * Two threads are started. One is serving udp->can routing and the other
444 * @return 0 on success, -1 otherwise
446 static int cegw_thread_start( void* data )
448 struct sockaddr_in udp_addr;
449 struct sockaddr_can can_addr;
450 struct cegw_setting* set;
452 set = (struct cegw_setting*)data;
454 can_addr.can_family = AF_CAN;
455 can_addr.can_ifindex = 0;
457 udp_addr.sin_family = AF_INET;
458 udp_addr.sin_port = htons( set->eth_port );
459 udp_addr.sin_addr = set->eth_ip;
462 mutex_lock( &cegw_mutex );
463 if( cegw_state == CEGW_EXIT )
465 /* stops threads if exist */
468 /* create and bind sockets */
469 if( sock_create_kern( PF_INET, SOCK_DGRAM, IPPROTO_UDP, &udp_sock) != 0 )
471 printk( KERN_ERR "canethgw: udp socket creation failed\n" );
475 if( sock_create_kern( PF_CAN, SOCK_RAW, CAN_RAW, &can_sock) != 0 )
477 printk( KERN_ERR "canethgw: can socket creation failed\n" );
481 if( kernel_bind( udp_sock, (struct sockaddr*)&udp_addr, sizeof( udp_addr ) ) != 0 )
483 printk( KERN_ERR "canethgw: udp socket binding failed\n" );
484 sock_release( udp_sock );
485 sock_release( can_sock );
489 if( kernel_bind( can_sock, (struct sockaddr*) &can_addr, sizeof(can_addr) ) != 0 )
491 printk( KERN_ERR "canethgw: can socket binding failed\n" );
492 kernel_sock_shutdown( udp_sock, SHUT_RDWR );
493 sock_release( udp_sock );
494 sock_release( can_sock );
499 cegw_state = CEGW_RUN;
501 eth_to_can = kthread_create( cegw_udp_can, NULL, "canethgw" );
502 if( IS_ERR( eth_to_can ) )
504 cegw_state = CEGW_STOP;
505 sock_release( udp_sock );
506 sock_release( can_sock );
509 get_task_struct( eth_to_can );
510 wake_up_process( eth_to_can );
512 can_to_eth = kthread_create( cegw_can_udp, NULL, "canethgw" );
513 if( IS_ERR( can_to_eth ) )
515 cegw_state = CEGW_STOP;
516 kernel_sock_shutdown( udp_sock, SHUT_RDWR );
517 kthread_stop( eth_to_can );
518 sock_release( udp_sock );
519 sock_release( can_sock );
522 /* ToDo: free this? */
523 get_task_struct( can_to_eth );
524 wake_up_process( can_to_eth );
526 mutex_unlock( &cegw_mutex );
527 pr_devel( "threads are running\n" );
533 * Waits for threads to stop. Does nothing if cegw_state == CEGW_STOP.
537 static int cegw_thread_stop( void )
540 struct sock* sk = NULL;
542 if( cegw_state == CEGW_STOP )
545 cegw_state = CEGW_STOP;
546 /* shut down socket */
550 sk->sk_shutdown |= how;
551 sk->sk_state_change( sk );
554 kernel_sock_shutdown( udp_sock, SHUT_RDWR );
556 /* wait for return to reuse port if restart */
557 kthread_stop( eth_to_can );
558 kthread_stop( can_to_eth );
559 sock_release( udp_sock );
560 sock_release( can_sock );
567 static int __init cegw_init( void )
569 /* subscribe to netlink */
570 rtnl_register( PF_CAN, RTM_GETROUTE, NULL, cegw_dump_job, NULL );
571 rtnl_register( PF_CAN, RTM_NEWROUTE, cegw_create_job, NULL, NULL );
572 rtnl_register( PF_CAN, RTM_DELROUTE, cegw_remove_job, NULL, NULL );
577 static void __exit cegw_exit( void )
579 /* ToDo: effect on cangw? */
580 rtnl_unregister_all( PF_CAN );
582 /* wait for rtnl callbacks */
586 mutex_lock( &cegw_mutex );
588 cegw_state = CEGW_EXIT;
589 mutex_unlock( &cegw_mutex );
594 module_init( cegw_init );
595 module_exit( cegw_exit );