]> rtime.felk.cvut.cz Git - can-eth-gw.git/commitdiff
Sending socket fd over netlink
authorRadek Matějka <radek.matejka@gmail.com>
Wed, 28 Nov 2012 21:19:37 +0000 (15:19 -0600)
committerRadek Matějka <radek.matejka@gmail.com>
Wed, 28 Nov 2012 21:19:37 +0000 (15:19 -0600)
The code is crudely modified to test the new approach: create
sockets in user-space and send their file descriptors to kernel
over netlink.

kernel/canethgw.c
kernel/canethgw.h
utils/cegw/cegw.c

index 36c38be89f4e5e66db19c2b83345614c2736707a..601ea7771bd77a46e9477756c1d85d163c71743e 100644 (file)
@@ -31,6 +31,9 @@ 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,
@@ -52,6 +55,7 @@ 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;
 
@@ -205,6 +209,7 @@ 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;
@@ -220,11 +225,36 @@ 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]) {
@@ -466,97 +496,68 @@ static int cegw_notifier(struct notifier_block *nb, unsigned long msg, void *dat
        return NOTIFY_DONE;
 }
 
-/**
- * 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)
+static int cegw_thread_recv_udp(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;
+       struct can_frame cf;
+       struct kvec vec;
+       struct msghdr mh;
+       struct sockaddr_in sa;
+       struct hlist_node* pos;
+       int can_ifidx;
+       int recv_size;
 
-       udp_addr.sin_family = AF_INET;
-       udp_addr.sin_port = htons(set->eth_port);
-       udp_addr.sin_addr = set->eth_ip;
+       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;
 
-       kfree(data);
-       mutex_lock(&cegw_mutex);
-       if (cegw_state == CEGW_EXIT)
-               goto out_err;
+       printk( "udp receiving\n" );
 
-       /* stops threads if exist */
-       cegw_thread_stop();
+       while( 1 )
+       {
+               vec.iov_base = &cf;
+               vec.iov_len = sizeof(cf);
 
-       /* 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;
+               recv_size = kernel_recvmsg(s_eth, &mh, &vec, 1,
+                               sizeof(cf), 0);
+               printk("udp status=%i\n", recv_size);
        }
 
-       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;
-       }
+       return 0;
+}
 
-       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;
-       }
+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;
 
-       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;
-       }
+       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;
 
-       /* start threads */
-       cegw_state = CEGW_RUN;
+       printk( "can receiving\n" );
 
-       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;
+       while( 1 )
+       {
+               vec.iov_base = &cf;
+               vec.iov_len = sizeof(cf);
+
+               recv_size = kernel_recvmsg(s_can, &mh, &vec, 1,
+                               sizeof(cf), 0);
+               printk("can status=%i\n", recv_size);
        }
-       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;
 }
 
 /**
index 85061e54594d4a882d70a5a1d7ec9ca362300d79..10f745a8392da509688c3d9b59e36971b5433a5f 100644 (file)
@@ -28,6 +28,8 @@ enum {
        CEGW_ETH_IP,
        CEGW_ETH_PORT,
        CEGW_CMD_INFO,
+       CEGW_CAN_SOCK,
+       CEGW_ETH_SOCK,
        __CEGW_MAX
 };
 #define CEGW_MAX (__CEGW_MAX - 1)
index c5c27b8c7d27a81084034f389032577d2293054b..fc91a9ce48a9672b38f2001ba9be5bf7eefe205c 100644 (file)
@@ -45,7 +45,7 @@ struct cegw_data
        unsigned short eth_listen_port;
 };
 
-struct cegw_nlmsg 
+struct cegw_nlmsg
 {
        struct nlmsghdr nh;
        struct rtmsg rt;
@@ -62,7 +62,7 @@ struct list_item
 
 unsigned int cegw_errno = 0;
 
-enum 
+enum
 {
        CEGW_ERR_UNKNOWN,
        CEGW_ERR_IF_UNSPEC,
@@ -121,7 +121,7 @@ int read_addrport( char* in, struct in_addr* addr, unsigned short* port )
        char* delim = NULL;
        char addrstr[16];
        int addrlen;
-       
+
        if( (delim = strchr( in, ':' )) == NULL )
        {
                cegw_errno = CEGW_ERR_COLON;
@@ -159,7 +159,7 @@ int read_addrport( char* in, struct in_addr* addr, unsigned short* port )
 char* read_iftype( char* in, int* iftype )
 {
        char* ret = in+4;
-       
+
        if( strncmp( "udp@", optarg, 4 ) == 0 )
        {
                *iftype = IF_ETH_UDP;
@@ -176,7 +176,7 @@ char* read_iftype( char* in, int* iftype )
                *iftype = IF_CAN;
                return ret;
        }
-       
+
        cegw_errno = CEGW_ERR_IF_TYPE;
        return NULL;
 }
@@ -266,7 +266,7 @@ 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;
 }
 
@@ -323,80 +323,40 @@ int main( int argc, char* argv[] )
        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) );
 
-       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;
+       /* create sockets for gateway  */
+       gw_eth_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       gw_can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
 
-               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;
-               }                               
-       }
+       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" );
+
+       gw_eth_addr.sin_family = AF_INET;
+       gw_eth_addr.sin_port = htons( 10501 );
+       gw_eth_addr.sin_addr.s_addr = INADDR_ANY;
+
+       gw_can_addr.can_family = AF_CAN;
+       gw_can_addr.can_ifindex = 0;
+
+       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" );
+
+       printf( "sockets created (%i,%i)\n", gw_can_sock, gw_eth_sock );
 
        /* prepare netlink message */
        req.nh.nlmsg_len   = NLMSG_LENGTH( sizeof(struct rtmsg) );
-       //req.nh.nlmsg_type;
+       req.nh.nlmsg_type  = RTM_NEWROUTE;
        req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        req.nh.nlmsg_seq   = 0;
        req.nh.nlmsg_pid   = 0; /* ? */
@@ -404,50 +364,27 @@ int main( int argc, char* argv[] )
        memset( &req.rt, 0, sizeof(req.rt) );
        req.rt.rtm_family = AF_CAN;
 
-       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;
-       }
+       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") );
 
        /* 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 )
@@ -457,6 +394,14 @@ int main( int argc, char* argv[] )
        }
        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 );