]> rtime.felk.cvut.cz Git - can-eth-gw.git/commitdiff
passing parameters to kernel via ioctl
authorRadek Matějka <radek.matejka@gmail.com>
Sun, 9 Dec 2012 21:44:09 +0000 (15:44 -0600)
committerRadek Matějka <radek.matejka@gmail.com>
Sun, 9 Dec 2012 21:44:09 +0000 (15:44 -0600)
Gateway is functional, but leaks resources.

distro/customroot/lib/libcrypto.so.1.0.0 [deleted symlink]
distro/customroot/lib/libmix.so [deleted symlink]
distro/customroot/lib/libpcap.so.1 [deleted symlink]
distro/customroot/lib/libz.so.1 [changed from symlink to file mode: 0644]
distro/customroot/sbin/tcpdump
kernel/Makefile
kernel/canethgw.c
kernel/canethgw.h
utils/cegw/Makefile
utils/cegw/cegw.c

diff --git a/distro/customroot/lib/libcrypto.so.1.0.0 b/distro/customroot/lib/libcrypto.so.1.0.0
deleted file mode 120000 (symlink)
index fa87914..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/usr/lib/libcrypto.so.1.0.0
\ No newline at end of file
diff --git a/distro/customroot/lib/libmix.so b/distro/customroot/lib/libmix.so
deleted file mode 120000 (symlink)
index b728356..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/usr/lib/libmix.so
\ No newline at end of file
diff --git a/distro/customroot/lib/libpcap.so.1 b/distro/customroot/lib/libpcap.so.1
deleted file mode 120000 (symlink)
index bc88273..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/usr/lib/libpcap.so.1
\ No newline at end of file
deleted file mode 120000 (symlink)
index 8988e25cf19626f8a12541410b8710b4f94b3baf..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1 +0,0 @@
-/lib/libz.so.1
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..c1b511782c0c486e530944b8f384f3dc5683c61b
Binary files /dev/null and b/distro/customroot/lib/libz.so.1 differ
index d81b520fd7c481de3bb594ac7fd891466db9f2d4..20afd3365eadecf9625242557e8bb0c466d0efcc 100755 (executable)
Binary files a/distro/customroot/sbin/tcpdump and b/distro/customroot/sbin/tcpdump differ
index 7fe1007bf4be6ed60b9cabec339be9a9e1a90145..ea91e91112ccd6aee50d1a07a84925bffb194aae 100644 (file)
@@ -15,4 +15,5 @@ clean:
 bench:
        $(MAKE) KERNEL_DIR=../distro/kernel-bench
 debug:
-       $(MAKE) KERNEL_DIR=../distro/kernel-debug
+       $(MAKE) KERNEL_DIR=../distro/kernel-debug DEBUG_FLAGS+=-ggdb
+
index 6fd1630f870178d2c30b9b9b993b2820f429f229..0df1247f666a65fff162e1923fce26997f916c93 100644 (file)
@@ -25,10 +25,9 @@ MODULE_LICENSE("GPL");
 
 static int  cegw_udp2can(void *data);
 static void cegw_udp_send(struct socket *udp_sock, struct can_frame *cf,
-                         struct in_addr ipaddr, u16 port);
+               struct sockaddr_in* addr);
 static int  cegw_can2udp(void *data);
-static void cegw_can_send(struct socket *can_sock, struct can_frame *cf,
-                         int ifindex);
+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);
 
@@ -62,19 +61,13 @@ static DEFINE_MUTEX(rule_eth_can_mutex);
 static DEFINE_MUTEX(rule_can_eth_mutex);
 static DEFINE_MUTEX(cegw_mutex);
 
-static void cegw_udp_send(struct socket *udp_sock, struct can_frame *cf,
-                         struct in_addr ipaddr, u16 port)
+static void cegw_udp_send(struct socket *udp_sock, struct can_frame *cf, struct sockaddr_in* addr)
 {
        struct msghdr mh;
-       struct sockaddr_in addr;
        struct kvec vec;
 
-       addr.sin_family = AF_INET;
-       addr.sin_port = htons(port);
-       addr.sin_addr = ipaddr;
-
-       mh.msg_name = &addr;
-       mh.msg_namelen = sizeof(addr);
+       mh.msg_name = addr;
+       mh.msg_namelen = sizeof(*addr);
        mh.msg_control = NULL;
        mh.msg_controllen = 0;
        mh.msg_flags = 0;
@@ -86,18 +79,13 @@ static void cegw_udp_send(struct socket *udp_sock, struct can_frame *cf,
        kernel_sendmsg(udp_sock, &mh, &vec, 1, sizeof(*cf));
 }
 
-static void cegw_can_send(struct socket* can_sock, struct can_frame* cf,
-               int ifindex)
+static void cegw_can_send(struct socket* can_sock, struct can_frame* cf)
 {
        struct msghdr mh;
        struct kvec vec;
-       struct sockaddr_can addr;
 
-       addr.can_family = AF_CAN;
-       addr.can_ifindex = ifindex;
-
-       mh.msg_name = &addr;
-       mh.msg_namelen = sizeof(addr);
+       mh.msg_name = NULL;
+       mh.msg_namelen = 0;
        mh.msg_control = NULL;
        mh.msg_controllen = 0;
        mh.msg_flags = 0;
@@ -118,32 +106,30 @@ static int cegw_udp2can(void *data)
        struct can_frame cf;
        struct kvec vec;
        struct msghdr mh;
-       struct cegw_rule* rule;
-       struct hlist_node* pos;
-       int can_ifidx;
+       struct cegw_job *job = (struct cegw_job *)data;
+       struct socket *udp_sock = NULL, *can_sock = NULL;
        int recv_size;
 
        memset(&mh, 0, sizeof(mh));
+       udp_sock = job->udp_sock;
+       can_sock = job->can_sock;
 
-       while (cegw_state != CEGW_STOP) {
+       while (1) {
+               printk( "recv\n" );
                vec.iov_base = &cf;
                vec.iov_len = sizeof(cf);
                recv_size = kernel_recvmsg(udp_sock, &mh, &vec, 1,
                                sizeof(cf), 0);
-               /* recv_size == 0 when shutting down */
-               if (recv_size != sizeof(cf) || recv_size == 0)
-                       continue;
-               else if (recv_size < 0)
-                       return -1;
+               /* if(recv_size != sizeof(cf) */
+               if (recv_size < 1) /* ToDo: split 0 and else */
+               {
+                       printk("udp2can error\n");
+                       break;
+               }
 
                /* FIXME: Convert endianing of cf.can_id */
-               mutex_lock(&rule_eth_can_mutex);
-               hlist_for_each_entry(rule, pos, &rule_eth_can, list) {
-                       can_ifidx = rule->can_ifindex;
-                       /* ToDo: from filter */
-                       cegw_can_send(can_sock, &cf, can_ifidx);
-               }
-               mutex_unlock(&rule_eth_can_mutex);
+               printk( "sendit to can\n" );
+               cegw_can_send(can_sock, &cf);
        }
 
        return 0;
@@ -159,284 +145,33 @@ static int cegw_can2udp(void* data)
        struct msghdr mh;
        struct kvec vec;
        struct can_frame cf;
-       struct sockaddr_can ca;
-       struct cegw_rule* rule;
-       struct hlist_node* pos;
-       struct in_addr eth_ip;
-       u16 eth_port;
+       struct cegw_job* job = (struct cegw_job*)data;
        int recv_size;
+       struct socket* udp_sock = job->udp_sock;
+       struct socket* can_sock = job->can_sock;
+       int i;
 
-       mh.msg_name = &ca;
-       mh.msg_namelen = sizeof(ca);
-       mh.msg_control = NULL;
-       mh.msg_controllen = 0;
-       mh.msg_flags = 0;
+       memset(&mh, 0, sizeof(mh));
 
-       while (cegw_state != CEGW_STOP) {
+       while (1) {
                vec.iov_base = &cf;
                vec.iov_len = sizeof(cf);
 
                recv_size = kernel_recvmsg(can_sock, &mh, &vec, 1,
                                           sizeof(cf), 0);
-               if (recv_size != sizeof(cf) || recv_size == 0)
-                       continue;
-               else if (recv_size < 0)
-                       return -1;
-
-               mutex_lock(&rule_can_eth_mutex);
-               hlist_for_each_entry(rule, pos, &rule_can_eth, list) {
-                       eth_ip = rule->eth_ip;
-                       eth_port = rule->eth_port;
-                       if (rule->can_ifindex == ca.can_ifindex)
-                               cegw_udp_send(udp_sock, &cf, eth_ip, eth_port);
-               }
-               mutex_unlock(&rule_can_eth_mutex);
-       }
-
-       return 0;
-}
-
-static int cegw_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
-{
-       struct nlattr* tb[ CEGW_MAX+1 ];
-       struct cegw_rule* rule = NULL;
-       int ifindex;
-       struct rtmsg* r;
-       struct in_addr ip;
-       unsigned short port;
-       struct cegw_setting* set;
-       int err = 0;
-
-       if (nlmsg_len(nlh) < sizeof(*r))
-               return -EINVAL;
-
-       r = nlmsg_data(nlh);
 
-       if (r->rtm_family != AF_CAN)
-               return -EPFNOSUPPORT;
-
-       err = nlmsg_parse(nlh, sizeof(*r), tb, CEGW_MAX, NULL);
-       if (err < 0) {
-               pr_devel("canethgw: nlmsg_parse error\n");
-               return err;
-       }
-
-       if (tb[CEGW_CMD_INFO] == NULL) {
-               pr_devel("canethgw: CEGW_CMD_INFO is missing in rtmsg\n");
-               return -EINVAL;
-       }
-
-       switch (*(int*)nla_data(tb[CEGW_CMD_INFO])) {
-       case CEGW_LISTEN:
-               if (!tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT]) {
-                       pr_devel("canethgw: missing attribute for CEGW_LISTEN\n");
-                       return -EINVAL;
-               }
-
-               /* ToDo: valid listen address */
-               set = kmalloc(sizeof(*set), GFP_KERNEL);
-               if (set == NULL)
-                       return -ENOMEM;
-               set->eth_ip   = *(struct in_addr*)nla_data(tb[CEGW_ETH_IP]);
-               set->eth_port = *(unsigned short*)nla_data(tb[CEGW_ETH_PORT]);
-               /* MS: It would be better to use workqueues here. */
-               kthread_run(cegw_thread_start, set, "canethgw");
-               break;
-       case CEGW_RULE_ETH_CAN:
-               if (!tb[CEGW_ETH_IP] || !tb[CEGW_ETH_PORT] ||
-                   !tb[CEGW_CAN_IFINDEX]) {
-                       pr_devel("canethgw: missing attribute for"
-                                "CEGW_RULE_ETH_CAN\n");
-                       return -EINVAL;
-               }
+               if (recv_size < 1)
+                       break;
 
-               ifindex = *(int*)nla_data(tb[CEGW_CAN_IFINDEX]);
-               ip = *(struct in_addr*)nla_data(tb[CEGW_ETH_IP]);
-               port = *(unsigned short*)nla_data(tb[CEGW_ETH_PORT]);
-               pr_devel("canethgw: new eth->can rule - (%x:%hu)->(%d)\n",
-                        ip.s_addr, port, ifindex);
-
-               rule = kmalloc(sizeof(struct cegw_rule), GFP_KERNEL);
-               if (rule == NULL)
-                       return -ENOMEM;
-
-               rule->can_ifindex = ifindex;
-               rule->eth_ip = ip;
-               rule->eth_port = port;
-
-               mutex_lock(&rule_eth_can_mutex);
-               hlist_add_head(&rule->list, &rule_eth_can);
-               mutex_unlock(&rule_eth_can_mutex);
-               break;
-       case CEGW_RULE_CAN_ETH:
-               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 -EINVAL;
+               for( i=0; i<job->udp_dstcnt; i++ )
+               {
+                       cegw_udp_send(udp_sock, &cf, &job->udp_dst[i]);
                }
-
-               ifindex = *(int*)nla_data(tb[CEGW_CAN_IFINDEX]);
-               ip = *(struct in_addr*)nla_data(tb[CEGW_ETH_IP]);
-               port = *(unsigned short*)nla_data(tb[CEGW_ETH_PORT]);
-               pr_devel("canethgw: new can->eth rule - (%d)->(%x:%hu)\n",
-                        ifindex, ip.s_addr, port);
-
-               rule = kmalloc(sizeof(struct cegw_rule), GFP_KERNEL);
-               if (rule == NULL)
-                       return -ENOMEM;
-
-               rule->can_ifindex = ifindex;
-               rule->eth_ip = ip;
-               rule->eth_port = port;
-
-               mutex_lock(&rule_can_eth_mutex);
-               hlist_add_head(&rule->list, &rule_can_eth);
-               mutex_unlock(&rule_can_eth_mutex);
-               break;
-       default:
-               pr_devel("canethgw: unknown CEGW_CMD_INFO\n");
-               break;
        }
 
        return 0;
 }
 
-static void cegw_flush(void)
-{
-       struct cegw_rule *rule;
-       struct hlist_node *pos, *n;
-
-       mutex_lock(&rule_eth_can_mutex);
-       hlist_for_each_entry_safe(rule, pos, n, &rule_eth_can, list) {
-               hlist_del(&rule->list);
-               kfree(rule);
-       }
-       mutex_unlock(&rule_eth_can_mutex);
-
-       mutex_lock(&rule_can_eth_mutex);
-       hlist_for_each_entry_safe(rule, pos, n, &rule_can_eth, list) {
-               hlist_del(&rule->list);
-               kfree(rule);
-       }
-       mutex_unlock(&rule_can_eth_mutex);
-}
-
-static int cegw_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
-{
-       struct rtmsg *r;
-       struct nlattr *tb[CEGW_MAX+1];
-       int err = 0;
-
-       if (nlmsg_len(nlh) < sizeof(*r))
-               return -EINVAL;
-
-       r = nlmsg_data(nlh);
-
-       if (r->rtm_family != AF_CAN)
-               return -EPFNOSUPPORT;
-
-       err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, CEGW_MAX, NULL);
-       if (err != 0)
-               return -EINVAL;
-
-       if (tb[CEGW_CMD_INFO] == NULL) {
-               pr_devel("canethgw: CEGW_CMD_INFO is missing in rtmsg\n");
-               return -EINVAL;
-       }
-
-       if (*(int*)nla_data(tb[CEGW_CMD_INFO]) != CEGW_FLUSH) {
-               return -EINVAL;
-       }
-
-       cegw_flush();
-
-       return 0;
-}
-
-static int cegw_put_rule(struct sk_buff *skb, int type, struct cegw_rule *rule)
-{
-       int ifindex;
-       struct in_addr ip;
-       unsigned short port;
-       struct nlmsghdr *nlh;
-
-       ifindex = rule->can_ifindex;
-       ip = rule->eth_ip;
-       port = rule->eth_port;
-
-       nlh = nlmsg_put(skb, 0, 0, 0, 0, 0);
-       if (nlh == NULL)
-               return -EMSGSIZE;
-
-       /* type */
-       if (nla_put(skb, CEGW_TYPE, sizeof(type), &type) < 0)
-               goto cancel;
-       else
-               nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(type));
-
-       /* can ifindex */
-       if (nla_put(skb, CEGW_CAN_IFINDEX, sizeof(ifindex), &ifindex) < 0)
-               goto cancel;
-       else
-               nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(ifindex));
-
-       /* ip adress */
-       if (nla_put(skb, CEGW_ETH_IP, sizeof(ip), &ip) < 0)
-               goto cancel;
-       else
-               nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(ip));
-
-       /* port */
-       if (nla_put(skb, CEGW_ETH_PORT, sizeof(port), &port) < 0)
-               goto cancel;
-       else
-               nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN(sizeof(port));
-
-       return skb->len;
-
-cancel:
-       nlmsg_cancel(skb, nlh);
-       return -EMSGSIZE;
-}
-
-static int cegw_getroute(struct sk_buff *skb, struct netlink_callback *cb)
-{
-       struct cegw_rule *rule;
-       struct hlist_node *pos;
-       int idx = 0;
-       int s_idx = cb->args[0];
-
-       mutex_lock(&rule_eth_can_mutex);
-       mutex_lock(&rule_can_eth_mutex);
-       hlist_for_each_entry(rule, pos, &rule_eth_can, list) {
-               if (idx < s_idx)
-                       goto cont1;
-
-               if (cegw_put_rule(skb, CEGW_RULE_ETH_CAN, rule) < 0)
-                       goto brk;
-cont1:
-               idx++;
-       }
-
-       hlist_for_each_entry(rule, pos, &rule_can_eth, list) {
-               if (idx < s_idx)
-                       goto cont2;
-
-               if (cegw_put_rule(skb, CEGW_RULE_CAN_ETH, rule) < 0)
-                       goto brk;
-cont2:
-               idx++;
-       }
-
-brk:
-       mutex_unlock(&rule_eth_can_mutex);
-       mutex_unlock(&rule_can_eth_mutex);
-       cb->args[0] = idx;
-
-       return skb->len;
-}
-
 static int cegw_notifier(struct notifier_block *nb, unsigned long msg, void *data)
 {
        struct net_device *dev = (struct net_device *)data;
@@ -476,88 +211,21 @@ static int cegw_notifier(struct notifier_block *nb, unsigned long msg, void *dat
  */
 static int cegw_thread_start(void *data)
 {
-       struct sockaddr_in udp_addr;
-       struct sockaddr_can can_addr;
-       struct cegw_setting *set;
-
-       set = (struct cegw_setting *)data;
-
-       can_addr.can_family = AF_CAN;
-       can_addr.can_ifindex = 0;
-
-       udp_addr.sin_family = AF_INET;
-       udp_addr.sin_port = htons(set->eth_port);
-       udp_addr.sin_addr = set->eth_ip;
-
-       kfree(data);
-       mutex_lock(&cegw_mutex);
-       if (cegw_state == CEGW_EXIT)
-               goto out_err;
-
-       /* stops threads if exist */
-       cegw_thread_stop();
-
-       /* 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;
-       }
-
-       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;
-       }
+       struct task_struct *task = NULL;
 
-       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);
+       task = kthread_run(cegw_udp2can, data, "canethgw_udp2can");
+       if (IS_ERR(task)) {
                goto out_err;
        }
 
-       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;
-       }
-
-       /* 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);
+       task = kthread_run(cegw_can2udp, data, "canethgw_can2udp");
+       if (IS_ERR(task)) {
                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 -ENOMEM;
 }
 
 /**
@@ -605,18 +273,74 @@ static int cegw_open(struct inode *inode, struct file *file)
 
 static int cegw_release(struct inode *inode, struct file *file)
 {
-       printk("cegw device released, data=%s\n", file->private_data);
+       struct cegw_job *job = (struct cegw_job *)file->private_data;
+
+       sock_release( job->udp_sock );
+       sock_release( job->can_sock );
+       printk("cegw device released, data=%s\n", (char *)file->private_data);
        return 0;
 }
 
 static long cegw_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       int err = 0;
+       int memsz = 0;
+       __u32 dstcnt = 0;
+       __u32 addrlen = 0;
+       struct cegw_ioctl *gwctl = NULL;
+       struct cegw_job *job = NULL;
+
+       /* ToDo: verify access and authorization */
+       if( get_user(dstcnt, &((struct cegw_ioctl __user *)arg)->udp_dstcnt) != 0 )
+               return -EFAULT;
+       if( get_user(addrlen, &((struct cegw_ioctl __user *)arg)->udp_addrlen) != 0 )
+               return -EFAULT;
+
+       memsz = sizeof(*gwctl) + dstcnt * addrlen;
+       /* ToDo: memory limit */
+       gwctl = kmalloc(GFP_KERNEL, memsz);
+       if (gwctl==NULL)
+               return -ENOMEM;
+
+       err = copy_from_user(gwctl, (void __user *)arg, memsz);
+       if (err != 0)
+       {
+               return -EFAULT;
+       }
+       /**/
+       job = kmalloc(GFP_KERNEL, sizeof(*job));
+       if (job == NULL)
+               return -ENOMEM;
+
+       job->udp_dst = kmalloc(GFP_KERNEL, dstcnt * addrlen); /* ToDo: limit */
+       if (job->udp_dst == NULL)
+               return -ENOMEM;
+
+       err = copy_from_user(job->udp_dst, (void __user *)(arg + sizeof(struct cegw_ioctl)), dstcnt*addrlen);
+       if (err != 0)
+               return -EFAULT;
+
+       job->udp_sock = sockfd_lookup( gwctl->udp_sock, &err );
+       if (job->udp_sock == NULL)
+               return err;
+
+       job->can_sock = sockfd_lookup( gwctl->can_sock, &err );
+       if (job->can_sock == NULL)
+               return err;
+
+       job->udp_dstcnt = dstcnt;
+
+       /* ToDo: sin_family? */
+
+       file->private_data = job;
+       cegw_thread_start(job);
+
+       /* process udp destinations */
        switch (cmd) {
-               case CEGW_IOCTL_CAN_SOCK:
-                       printk("ioctl can sock\n");
-                       break;
-               case CEGW_IOCTL_UDP_SOCK:
-                       printk("ioctl udp sock\n");
+               case CEGW_IOCTL_START:
+                       printk("udp_dstcnt=%i\n", gwctl->udp_dstcnt);
+                       printk("udp_dst[0] family=%i\n", job->udp_dst[0].sin_family);
+                       printk("udp_dst[1] family=%i\n", job->udp_dst[1].sin_family);
                        break;
                default:
                        printk("undefined ioctl command\n");
@@ -647,11 +371,6 @@ static int __init cegw_init(void)
        notifier.notifier_call = cegw_notifier;
        register_netdevice_notifier(&notifier);
 
-       /* subscribe to netlink */
-       rtnl_register(PF_CAN, RTM_GETROUTE, NULL, cegw_getroute, NULL);
-       rtnl_register(PF_CAN, RTM_NEWROUTE, cegw_newroute, NULL, NULL);
-       rtnl_register(PF_CAN, RTM_DELROUTE, cegw_delroute, NULL, NULL);
-
        return 0;
 }
 
@@ -673,7 +392,7 @@ static void __exit cegw_exit(void)
        mutex_unlock(&cegw_mutex);
 
        unregister_netdevice_notifier(&notifier);
-       cegw_flush();
+       //cegw_flush();
 }
 
 module_init(cegw_init);
index 4381bda47e68faf2f460666a9b62c19f487a1f62..c082fcac57951dd492b723afc9123a1611c7e733 100644 (file)
@@ -4,10 +4,6 @@
 #include <linux/types.h>
 #include <linux/can.h>
 
-#define CEGW_IOCTL_BASE 'c'
-#define CEGW_IOCTL_CAN_SOCK _IOW(CEGW_IOCTL_BASE, 0, int)
-#define CEGW_IOCTL_UDP_SOCK _IOW(CEGW_IOCTL_BASE, 1, int)
-
 /* these are from gw.h */
 struct rtcanmsg {
        __u8  can_family;
@@ -36,6 +32,38 @@ enum {
 };
 #define CEGW_MAX (__CEGW_MAX - 1)
 
+struct cegw_udp_dst
+{
+       __u32 len;
+       struct sockaddr addr;
+};
+
+struct cegw_udp_dst4
+{
+       __u32 len;
+       struct sockaddr_in addr;
+};
+
+struct cegw_ioctl
+{
+       __u32 can_sock;
+       __u32 udp_sock;;
+       __u32 udp_dstcnt;
+       __u32 udp_addrlen;
+       struct sockaddr_in udp_dst[0];
+};
+
+struct cegw_job
+{
+       struct socket* can_sock;
+       struct socket* udp_sock;
+       __u32  udp_dstcnt;
+       struct sockaddr_in* udp_dst;
+};
+
+#define CEGW_IOCTL_BASE 'c'
+#define CEGW_IOCTL_START _IOW(CEGW_IOCTL_BASE, 0, struct cegw_ioctl)
+
 /* ToDo:
  *     CEGW_HANDLED
  *     CEGW_DROPPED
index b6001c99449c8251fc90f22b27d5b8a42ee67997..5fe6d86064f5f3d23cb3b6760e20c7a8789fc632 100644 (file)
@@ -1,3 +1,3 @@
 all:
-       gcc -Wall -ggdb -ocegw -I../../kernel cegw.c -lnetlink
+       gcc -Wall -ggdb -ocegw -D_DEBUG -I../../kernel cegw.c -lnetlink
 
index 73726346e291b69096afb0dcedd4c5a606dd9e18..566a09f8ba909675e151a58cf8fe35093fef42be 100644 (file)
@@ -12,6 +12,7 @@
 #include <arpa/inet.h>
 #include <linux/can.h>
 #include <linux/types.h>
+#include <limits.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -49,7 +50,7 @@ struct cegw_data
        unsigned short eth_listen_port;
 };
 
-struct cegw_nlmsg 
+struct cegw_nlmsg
 {
        struct nlmsghdr nh;
        struct rtmsg rt;
@@ -66,7 +67,7 @@ struct list_item
 
 unsigned int cegw_errno = 0;
 
-enum 
+enum
 {
        CEGW_ERR_UNKNOWN,
        CEGW_ERR_IF_UNSPEC,
@@ -230,85 +231,6 @@ int read_if( char* in, int* iftype, struct cegw_data* d )
        return 0;
 }
 
-inline static int cegw_add( struct cegw_nlmsg* req, struct cegw_data* d )
-{
-       int gwtype = 0;
-
-       req->nh.nlmsg_type  = RTM_NEWROUTE;
-       if( (d->src_if == 0 || d->dst_if == 0) )
-       {
-               cegw_errno = CEGW_ERR_IF_UNSPEC;
-               return -cegw_errno;
-       }
-
-       if( d->src_if == d->dst_if )
-       {
-               cegw_errno = CEGW_ERR_IF_SAME;
-               return -cegw_errno;
-       }
-
-       gwtype = (d->src_if == IF_CAN) ? CEGW_RULE_CAN_ETH : CEGW_RULE_ETH_CAN;
-       addattr_l( &req->nh, sizeof(*req), CEGW_CAN_IFINDEX, &d->can_ifidx, sizeof(d->can_ifidx) );
-       addattr_l( &req->nh, sizeof(*req), CEGW_ETH_IP, &d->eth_addr, sizeof(d->eth_addr) );
-       addattr_l( &req->nh, sizeof(*req), CEGW_ETH_PORT, &d->eth_port, sizeof(d->eth_port) );
-       addattr32( &req->nh, sizeof(*req), CEGW_CMD_INFO, gwtype );
-
-       return 0;
-}
-
-inline static int cegw_listen( struct cegw_nlmsg* req, struct cegw_data* d )
-{
-       req->nh.nlmsg_type = RTM_NEWROUTE;
-       addattr32( &req->nh, sizeof(*req), CEGW_CMD_INFO, CEGW_LISTEN );
-       addattr_l( &req->nh, sizeof(*req), CEGW_ETH_IP, &d->eth_listen_addr, sizeof(d->eth_listen_addr) );
-       addattr_l( &req->nh, sizeof(*req), CEGW_ETH_PORT, &d->eth_listen_port, sizeof(d->eth_listen_port) );
-
-       return 0;
-}
-
-inline static int cegw_list( struct cegw_nlmsg* req, struct cegw_data* d )
-{
-       req->nh.nlmsg_type = RTM_GETROUTE;
-       req->nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-       
-       return 0;
-}
-
-inline static int cegw_flush( struct cegw_nlmsg* req, struct cegw_data* d )
-{
-       addattr32( &req->nh, sizeof(*req), CEGW_CMD_INFO, CEGW_FLUSH );
-       req->nh.nlmsg_type  = RTM_DELROUTE;
-       return 0;
-}
-
-void print_list_item( struct list_item* li )
-{
-       char ifname[IF_NAMESIZE];
-       const char src_width = 21;
-       char* dotaddr;
-       int tmp;
-
-       if( if_indextoname( li->can, ifname ) == NULL )
-       {
-               strncpy( ifname, "unknown", IF_NAMESIZE );
-       }
-
-       /* ToDo listening at */
-       switch( li->type )
-       {
-               case CEGW_RULE_CAN_ETH:
-                       printf( "can@%-*s -> udp@%s:%hu\n", src_width, ifname, \
-                                inet_ntoa(li->ip), li->port );
-                       break;
-               case CEGW_RULE_ETH_CAN:
-                       dotaddr = inet_ntoa(li->ip);
-                       tmp = src_width - strlen(dotaddr) - 1;
-                       printf( "udp@%s:%-*hu -> can@%s\n", inet_ntoa(li->ip), \
-                                tmp, li->port, ifname );
-                       break;
-       }
-}
-
 int main( int argc, char* argv[] )
 {
        int s;
@@ -327,211 +249,112 @@ int main( int argc, char* argv[] )
        struct rtattr* rta;
        int len;
        struct list_item li;
+       int udp_sock, can_sock;
+       struct sockaddr_in udp_addr;
+       struct sockaddr_can can_addr;
+       struct in_addr ipaddr;
+       unsigned short port;
+       int i;
+       struct sockaddr_in* dst = NULL;
 
-       /**/
-       int fd;
-
-       fd = open( "/dev/cegw", O_RDONLY );
-       if( fd == -1 )
+       if( argc < 3 )
        {
-               fprintf( stderr, "error: could not open device file\n" );
-               return -1;
+               perr( "not enought arguments" );
+               /* ToDo: print usage */
+               return;
        }
 
-       ioctl( fd, CEGW_IOCTL_CAN_SOCK, 8 );
-       close( fd );
-       return 0;
-
-       memset( &d, 0, sizeof(d) );
+       int dstcnt = argc-3;
+#ifdef _DEBUG
+       printf( "dstcnt=%i\n", dstcnt );
+#endif
+       struct cegw_ioctl* gwctl = (struct cegw_ioctl*)malloc( sizeof(*gwctl) + (dstcnt)*sizeof(struct sockaddr_in) );
 
-       struct option long_opt[] =
+       for( i=1; i<argc; i++ )
        {
-               { "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;
-
-               switch( opt )
+               printf( "%s\n", argv[i] );
+               switch( i )
                {
-                       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;
-                               }
+                       case 1: /* can */
+                               can_addr.can_family = AF_CAN;
+                               can_addr.can_ifindex = if_nametoindex( argv[i] ); /* ToDo */
                                break;
-                       case 's':
-                               if( read_if( optarg, &d.src_if, &d ) != 0 )
+                       case 2: /* listen addr */
+                               udp_addr.sin_family = AF_INET;
+                               if( read_addrport(argv[i], &udp_addr.sin_addr, &port) != 0 )
                                {
-                                       perr( "'-s'" );
-                                       return -1;
+                                       perr( "listening address mismatch" );
+                                       /* ToDo: free gwctl, all branches */
                                }
+                               udp_addr.sin_port = htons(port);
                                break;
-                       case 'd':
-                               if( read_if( optarg, &d.dst_if, &d ) != 0 )
+                       default: /* udp destination */
+                               dst = &gwctl->udp_dst[i-3];
+                               dst->sin_family = AF_INET;
+                               if( read_addrport(argv[i], &dst->sin_addr, &port) != 0 )
                                {
-                                       perr( "'-d'" );
-                                       return -1;
+                                       perr( "udp destination mismatch" );
                                }
+                               dst->sin_port = htons(port);
                                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;
-       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;
-
-       switch( cmd )
+       /* udp socket */
+       udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       if( udp_sock == -1 )
        {
-               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;
+               fprintf( stderr, "error: udp socket(..) failed\n" );
+               return -1;
        }
 
-       /* 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, 
-                     (struct sockaddr*)&nladdr, sizeof(nladdr) );
-       if( err < 0 )
+       printf( "port:%x\n", udp_addr.sin_port );
+       if(bind( udp_sock, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr_in) ) != 0)
        {
-               perror( "netlink sendto" );
+               fprintf( stderr, "error: udp bind(..) failed\n" );
                return -1;
        }
-       
-       /* recv */
-       rsize = recv( s, &rxbuf, sizeof(rxbuf), 0 );
-       if( rsize < 0 )
+
+       /* can socket */
+       /* ToDo: name lookup error */
+       can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+       if( can_sock == -1 )
        {
-               perr( "recv" );
+               fprintf( stderr, "error: can socket(..) failed\n" );
                return -1;
        }
-       nlh = (struct nlmsghdr*)rxbuf;
 
-       if( nlh->nlmsg_type == NLMSG_ERROR )
+       if( bind(can_sock, (struct sockaddr *)&can_addr, sizeof(struct sockaddr_can)) != 0 )
        {
-               rte = (struct nlmsgerr*)NLMSG_DATA( nlh );
-               err = rte->error;
+               fprintf( stderr, "error: can bind(..) failed\n" );
+               return -1;
+       }
 
-               if( err == 0  )
-               {
-                       printf( "%s\n", strerror(abs(err)) );
-                       return 0;
-               } else
-               {
-                       printf( "netlink error: %s\n", strerror(abs(err)) );
-                       return -1;
-               }
+       /* send it to kernel gateway */
+       int fd;
+
+       fd = open( "/dev/cegw", O_RDONLY );
+       if( fd == -1 )
+       {
+               fprintf( stderr, "error: could not open device file\n" );
+               return -1;
        }
 
-       if( cmd & CEGW_CMD_LIST )
+       gwctl->can_sock = can_sock;
+       gwctl->udp_sock = udp_sock;
+       gwctl->udp_dstcnt = dstcnt;
+       gwctl->udp_addrlen = sizeof(struct sockaddr_in);
+
+       if( ioctl( fd, CEGW_IOCTL_START, gwctl ) != 0 )
        {
-               /* ToDo recv while */
-               printf( "%10ssource%20sdestination\n", "", "" );
-               while( 1 )
-               {
-                       if( !NLMSG_OK( nlh, rsize ) )
-                       {
-                               break;
-                       }
-                       if( nlh->nlmsg_type == NLMSG_DONE )
-                       {
-                               break;
-                       }
-                       /* ToDo: NLMSG_ERR */
-                       rta = NLMSG_DATA( nlh );
-                       len = NLMSG_PAYLOAD( nlh, 0 );
-                       for( ;RTA_OK(rta, len); rta = RTA_NEXT(rta,len) )
-                       {
-                               switch( rta->rta_type )
-                               {
-                                       case CEGW_TYPE:
-                                               li.type = *(int*)RTA_DATA(rta);
-                                               break;
-                                       case CEGW_CAN_IFINDEX:
-                                               li.can = *(int*)RTA_DATA(rta);
-                                               break;
-                                       case CEGW_ETH_IP:
-                                               li.ip = *(struct in_addr*)RTA_DATA(rta);
-                                               break;
-                                       case CEGW_ETH_PORT:
-                                               li.port = *(unsigned short*)RTA_DATA(rta);
-                                               break;
-                                       /* case CGW_ETH_PROTO */
-                               }
-                       }
+               perror( NULL );
+       }
 
-                       print_list_item( &li );
+       //close( fd );
 
-                       nlh = NLMSG_NEXT( nlh, rsize );
-               }
+       while(1)
+       {
+               sleep( UINT_MAX );
        }
 
        return 0;