#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);