]> rtime.felk.cvut.cz Git - can-eth-gw.git/blobdiff - kernel/canethgw.c
canethgw micsdevice
[can-eth-gw.git] / kernel / canethgw.c
index 601ea7771bd77a46e9477756c1d85d163c71743e..6fd1630f870178d2c30b9b9b993b2820f429f229 100644 (file)
@@ -18,6 +18,7 @@
 #include "canethgw.h"
 #include <linux/completion.h>
 #include <linux/mutex.h>
+#include <linux/miscdevice.h>
 #include <net/inet_common.h>
 
 MODULE_LICENSE("GPL");
@@ -31,9 +32,6 @@ static void cegw_can_send(struct socket *can_sock, struct can_frame *cf,
 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,
@@ -55,7 +53,6 @@ struct cegw_setting {
 
 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;
 
@@ -209,7 +206,6 @@ static int cegw_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        unsigned short port;
        struct cegw_setting* set;
        int err = 0;
-       int fd_eth, fd_can;
 
        if (nlmsg_len(nlh) < sizeof(*r))
                return -EINVAL;
@@ -225,36 +221,11 @@ static int cegw_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                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]) {
@@ -272,7 +243,7 @@ static int cegw_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                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");
@@ -298,7 +269,7 @@ static int cegw_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                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");
@@ -496,68 +467,97 @@ static int cegw_notifier(struct notifier_block *nb, unsigned long msg, void *dat
        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;
 }
 
 /**
@@ -595,8 +595,55 @@ static int cegw_thread_stop(void)
        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(&notifier);
 
@@ -610,6 +657,9 @@ static int __init cegw_init(void)
 
 static void __exit cegw_exit(void)
 {
+       misc_deregister(&cegw_device);
+
+       return;
        /* ToDo: effect on cangw? */
        rtnl_unregister_all(PF_CAN);