#include "canethgw.h"
#include <linux/completion.h>
#include <linux/mutex.h>
+#include <linux/miscdevice.h>
#include <net/inet_common.h>
MODULE_LICENSE("GPL");
static int cegw_thread_start(void *data);
static int cegw_thread_stop(void);
-static int cegw_thread_recv_udp(void *data);
-static int cegw_thread_recv_can(void *data);
-
enum __cegw_state {
CEGW_RUN,
CEGW_STOP,
static int cegw_state = CEGW_STOP;
static struct socket *can_sock = NULL, *udp_sock = NULL;
-static struct socket *s_can = NULL, *s_eth = NULL;
static struct task_struct *eth_to_can = NULL, *can_to_eth = NULL;
static struct notifier_block notifier;
unsigned short port;
struct cegw_setting* set;
int err = 0;
- int fd_eth, fd_can;
if (nlmsg_len(nlh) < sizeof(*r))
return -EINVAL;
return err;
}
- fd_eth = *(int*)nla_data(tb[CEGW_ETH_SOCK]);
- fd_can = *(int*)nla_data(tb[CEGW_CAN_SOCK]);
-
- printk( "cegw: sock=%i,%i\n", fd_eth, fd_can );
-
- s_can = sockfd_lookup( fd_can, &err );
- s_eth = sockfd_lookup( fd_eth, &err );
-
- if( s_can == NULL || s_eth == NULL )
- {
- printk( "error: socket look-up failed\n" );
- return 0;
- }
-
- struct can_frame greet;
- greet.can_id = 0;
- greet.can_dlc = 4;
- greet.data[0] = 7;
-
- //cegw_can_send( s_can, &greet, *(int*)nla_data(tb[CEGW_CAN_IFINDEX]) );
- kthread_run(cegw_thread_recv_udp, NULL, "canethgw");
- kthread_run(cegw_thread_recv_can, NULL, "canethgw");
- /*
if (tb[CEGW_CMD_INFO] == NULL) {
pr_devel("canethgw: CEGW_CMD_INFO is missing in rtmsg\n");
return -EINVAL;
}
- */
- return 0;
switch (*(int*)nla_data(tb[CEGW_CMD_INFO])) {
case CEGW_LISTEN:
if (!tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT]) {
kthread_run(cegw_thread_start, set, "canethgw");
break;
case CEGW_RULE_ETH_CAN:
- if (!tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] ||
+ if (!tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] ||
!tb[CEGW_CAN_IFINDEX]) {
pr_devel("canethgw: missing attribute for"
"CEGW_RULE_ETH_CAN\n");
mutex_unlock(&rule_eth_can_mutex);
break;
case CEGW_RULE_CAN_ETH:
- if (!tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] ||
+ if (!tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] ||
!tb[CEGW_CAN_IFINDEX]) {
pr_devel("canethgw: missing attribute for "
"CEGW_RULE_CAN_ETH\n");
return NOTIFY_DONE;
}
-static int cegw_thread_recv_udp(void *data)
+/**
+ * cegw_thread_start - start working threads
+ * @data: (struct cegw_setting *) with new listening address
+ *
+ * Two threads are started. One is serving udp->can routing and the other
+ * can->udp.
+ */
+static int cegw_thread_start(void *data)
{
- struct can_frame cf;
- struct kvec vec;
- struct msghdr mh;
- struct sockaddr_in sa;
- struct hlist_node* pos;
- int can_ifidx;
- int recv_size;
+ struct sockaddr_in udp_addr;
+ struct sockaddr_can can_addr;
+ struct cegw_setting *set;
- memset(&mh, 0, sizeof(mh));
- mh.msg_name = &sa;
- mh.msg_namelen = sizeof(sa);
- mh.msg_control = NULL;
- mh.msg_controllen = 0;
- mh.msg_flags = 0;
+ set = (struct cegw_setting *)data;
- printk( "udp receiving\n" );
+ can_addr.can_family = AF_CAN;
+ can_addr.can_ifindex = 0;
- while( 1 )
- {
- vec.iov_base = &cf;
- vec.iov_len = sizeof(cf);
+ udp_addr.sin_family = AF_INET;
+ udp_addr.sin_port = htons(set->eth_port);
+ udp_addr.sin_addr = set->eth_ip;
- recv_size = kernel_recvmsg(s_eth, &mh, &vec, 1,
- sizeof(cf), 0);
- printk("udp status=%i\n", recv_size);
- }
+ kfree(data);
+ mutex_lock(&cegw_mutex);
+ if (cegw_state == CEGW_EXIT)
+ goto out_err;
- return 0;
-}
+ /* stops threads if exist */
+ cegw_thread_stop();
-static int cegw_thread_recv_can(void *data)
-{
- struct can_frame cf;
- struct kvec vec;
- struct msghdr mh;
- struct sockaddr_can ca;
- struct hlist_node* pos;
- int can_ifidx;
- int recv_size;
+ /* create and bind sockets */
+ if (sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &udp_sock)
+ != 0) {
+ printk(KERN_ERR "canethgw: udp socket creation failed\n");
+ goto out_err;
+ }
- memset(&mh, 0, sizeof(mh));
- mh.msg_name = &ca;
- mh.msg_namelen = sizeof(ca);
- mh.msg_control = NULL;
- mh.msg_controllen = 0;
- mh.msg_flags = 0;
+ if (sock_create_kern(PF_CAN, SOCK_RAW, CAN_RAW, &can_sock) != 0) {
+ printk(KERN_ERR "canethgw: can socket creation failed\n");
+ sock_release(udp_sock);
+ goto out_err;
+ }
- printk( "can receiving\n" );
+ if (kernel_bind(udp_sock, (struct sockaddr*)&udp_addr,
+ sizeof(udp_addr)) != 0) {
+ printk(KERN_ERR "canethgw: udp socket binding failed\n");
+ sock_release(udp_sock);
+ sock_release(can_sock);
+ goto out_err;
+ }
- while( 1 )
- {
- vec.iov_base = &cf;
- vec.iov_len = sizeof(cf);
+ if (kernel_bind(can_sock, (struct sockaddr*) &can_addr,
+ sizeof(can_addr)) != 0) {
+ printk(KERN_ERR "canethgw: can socket binding failed\n");
+ kernel_sock_shutdown(udp_sock, SHUT_RDWR);
+ sock_release(udp_sock);
+ sock_release(can_sock);
+ goto out_err;
+ }
- recv_size = kernel_recvmsg(s_can, &mh, &vec, 1,
- sizeof(cf), 0);
- printk("can status=%i\n", recv_size);
+ /* start threads */
+ cegw_state = CEGW_RUN;
+
+ eth_to_can = kthread_create(cegw_udp2can, NULL, "canethgw");
+ if (IS_ERR(eth_to_can)) {
+ cegw_state = CEGW_STOP;
+ sock_release(udp_sock);
+ sock_release(can_sock);
+ goto out_err;
}
+ get_task_struct(eth_to_can);
+ wake_up_process(eth_to_can);
+
+ can_to_eth = kthread_create(cegw_can2udp, NULL, "canethgw");
+ if (IS_ERR(can_to_eth)) {
+ cegw_state = CEGW_STOP;
+ kernel_sock_shutdown(udp_sock, SHUT_RDWR);
+ kthread_stop(eth_to_can);
+ sock_release(udp_sock);
+ sock_release(can_sock);
+ goto out_err;
+ }
+ get_task_struct(can_to_eth);
+ wake_up_process(can_to_eth);
+ mutex_unlock(&cegw_mutex);
+ pr_devel("threads are running\n");
return 0;
+out_err:
+ mutex_unlock(&cegw_mutex);
+ return -1;
}
/**
return 0;
}
+static int cegw_open(struct inode *inode, struct file *file)
+{
+ file->private_data = "greetings";
+
+ printk("cegw device opened\n");
+ return 0;
+}
+
+static int cegw_release(struct inode *inode, struct file *file)
+{
+ printk("cegw device released, data=%s\n", file->private_data);
+ return 0;
+}
+
+static long cegw_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case CEGW_IOCTL_CAN_SOCK:
+ printk("ioctl can sock\n");
+ break;
+ case CEGW_IOCTL_UDP_SOCK:
+ printk("ioctl udp sock\n");
+ break;
+ default:
+ printk("undefined ioctl command\n");
+ break;
+ }
+
+ return 0;
+}
+
+static const struct file_operations cegw_fops = {
+ .owner = THIS_MODULE,
+ .open = cegw_open,
+ .release = cegw_release,
+ .unlocked_ioctl = cegw_ioctl
+};
+
+static struct miscdevice cegw_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "cegw",
+ .fops = &cegw_fops
+};
+
static int __init cegw_init(void)
{
+ misc_register(&cegw_device);
+
+ return 0;
notifier.notifier_call = cegw_notifier;
register_netdevice_notifier(¬ifier);
static void __exit cegw_exit(void)
{
+ misc_deregister(&cegw_device);
+
+ return;
/* ToDo: effect on cangw? */
rtnl_unregister_all(PF_CAN);
#include <linux/can.h>
#include <linux/types.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
#include "canethgw.h"
/**
unsigned short eth_listen_port;
};
-struct cegw_nlmsg
+struct cegw_nlmsg
{
struct nlmsghdr nh;
struct rtmsg rt;
unsigned int cegw_errno = 0;
-enum
+enum
{
CEGW_ERR_UNKNOWN,
CEGW_ERR_IF_UNSPEC,
}
/**
- * read_addrport - parses @in for eth address.
+ * read_addrport - parses @in for eth address.
* Valid input is e.g. udp@127.0.0.1:10502 or can@vcan0.
*
* @param[in] in string to search in
{
req->nh.nlmsg_type = RTM_GETROUTE;
req->nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-
+
return 0;
}
struct rtattr* rta;
int len;
struct list_item li;
- int gw_can_sock = 0;
- int gw_eth_sock = 0;
- struct sockaddr_in gw_eth_addr;
- struct sockaddr_can gw_can_addr;
- struct in_addr addr;
-
- memset( &d, 0, sizeof(d) );
- /* create sockets for gateway */
- gw_eth_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
- gw_can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+ /**/
+ int fd;
- if( gw_eth_sock == -1 )
- fprintf( stderr, "error: udp socket for gw creation failed\n" );
- if( gw_can_sock == -1 )
- fprintf( stderr, "error: can socket for gw creation failed\n" );
+ fd = open( "/dev/cegw", O_RDONLY );
+ if( fd == -1 )
+ {
+ fprintf( stderr, "error: could not open device file\n" );
+ return -1;
+ }
- gw_eth_addr.sin_family = AF_INET;
- gw_eth_addr.sin_port = htons( 10501 );
- gw_eth_addr.sin_addr.s_addr = INADDR_ANY;
+ ioctl( fd, CEGW_IOCTL_CAN_SOCK, 8 );
+ close( fd );
+ return 0;
- gw_can_addr.can_family = AF_CAN;
- gw_can_addr.can_ifindex = 0;
+ memset( &d, 0, sizeof(d) );
- if( bind( gw_eth_sock, (struct sockaddr*)&gw_eth_addr, sizeof(gw_eth_addr) ) != 0 )
- fprintf( stderr, "error: eth binding\n" );
- if( bind( gw_can_sock, (struct sockaddr*)&gw_can_addr, sizeof(gw_can_addr) ) )
- fprintf( stderr, "error: can binding\n" );
+ struct option long_opt[] =
+ {
+ { "add" , 0, NULL, 'A' },
+ { "flush" , 0, NULL, 'F' },
+ { "list" , 0, NULL, 'L' },
+ { "listen", 1, NULL, 'l' },
+ { 0, 0, 0, 0 }
+ };
+
+ while( 1 )
+ {
+ opt = getopt_long( argc, argv, "AFLl:s:d:", long_opt, NULL );
+ if( opt == -1 )
+ break;
- printf( "sockets created (%i,%i)\n", gw_can_sock, gw_eth_sock );
+ switch( opt )
+ {
+ case 'A':
+ cmd |= CEGW_CMD_ADD;
+ break;
+ case 'F':
+ cmd |= CEGW_CMD_FLUSH;
+ break;
+ case 'L':
+ cmd |= CEGW_CMD_LIST;
+ break;
+ case 'l':
+ cmd |= CEGW_CMD_LISTEN;
+ if( (optstr = read_iftype( optarg, &tmp )) == NULL )
+ {
+ perr( "'--listen'" );
+ return -1;
+ }
+ if( tmp != IF_ETH_UDP )
+ {
+ perr( "'--listen' expects udp interface" );
+ return -1;
+ }
+ if( read_addrport( optstr, &d.eth_listen_addr, &d.eth_listen_port ) )
+ {
+ perr( "'--listen'" );
+ return -1;
+ }
+ break;
+ case 's':
+ if( read_if( optarg, &d.src_if, &d ) != 0 )
+ {
+ perr( "'-s'" );
+ return -1;
+ }
+ break;
+ case 'd':
+ if( read_if( optarg, &d.dst_if, &d ) != 0 )
+ {
+ perr( "'-d'" );
+ return -1;
+ }
+ break;
+ case '?':
+ return -1;
+ break;
+ default:
+ perr( "unknown option" );
+ return -1;
+ break;
+ }
+ }
/* prepare netlink message */
req.nh.nlmsg_len = NLMSG_LENGTH( sizeof(struct rtmsg) );
- req.nh.nlmsg_type = RTM_NEWROUTE;
+ //req.nh.nlmsg_type;
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.nh.nlmsg_seq = 0;
req.nh.nlmsg_pid = 0; /* ? */
memset( &req.rt, 0, sizeof(req.rt) );
req.rt.rtm_family = AF_CAN;
- addattr32( &req.nh, sizeof(req), CEGW_CAN_SOCK, gw_can_sock );
- addattr32( &req.nh, sizeof(req), CEGW_ETH_SOCK, gw_eth_sock );
- addattr32( &req.nh, sizeof(req), CEGW_CAN_IFINDEX, if_nametoindex("vcan0") );
+ switch( cmd )
+ {
+ case 0:
+ perr( "command not specified" );
+ return -1;
+ 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:
+ perr( "command mismatch" );
+ break;
+ }
/* send over netlink socket */
s = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); /* chck */
-
+
memset( &nladdr, 0, sizeof(nladdr) );
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pad = 0;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
- err = sendto( s, &req, req.nh.nlmsg_len, 0,
+ err = sendto( s, &req, req.nh.nlmsg_len, 0,
(struct sockaddr*)&nladdr, sizeof(nladdr) );
if( err < 0 )
{
perror( "netlink sendto" );
return -1;
}
-
+
/* recv */
rsize = recv( s, &rxbuf, sizeof(rxbuf), 0 );
if( rsize < 0 )
}
nlh = (struct nlmsghdr*)rxbuf;
- /* REMOVE */
- sleep( 2 );
- //printf( "closing sockets\n" );
- //shutdown( gw_eth_sock, SHUT_RDWR );
- shutdown( gw_can_sock, SHUT_RDWR );
- //close( gw_can_sock );
- //close( gw_eth_sock );
-
if( nlh->nlmsg_type == NLMSG_ERROR )
{
rte = (struct nlmsgerr*)NLMSG_DATA( nlh );