From: Radek Matějka Date: Wed, 28 Nov 2012 21:19:37 +0000 (-0600) Subject: Sending socket fd over netlink X-Git-Url: http://rtime.felk.cvut.cz/gitweb/can-eth-gw.git/commitdiff_plain/5e832b957fdc026b489fe085ebbe8630eb36183b Sending socket fd over netlink The code is crudely modified to test the new approach: create sockets in user-space and send their file descriptors to kernel over netlink. --- diff --git a/kernel/canethgw.c b/kernel/canethgw.c index 36c38be..601ea77 100644 --- a/kernel/canethgw.c +++ b/kernel/canethgw.c @@ -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; } /** diff --git a/kernel/canethgw.h b/kernel/canethgw.h index 85061e5..10f745a 100644 --- a/kernel/canethgw.h +++ b/kernel/canethgw.h @@ -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) diff --git a/utils/cegw/cegw.c b/utils/cegw/cegw.c index c5c27b8..fc91a9c 100644 --- a/utils/cegw/cegw.c +++ b/utils/cegw/cegw.c @@ -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 );