#include "canethgw.h"
/**
- * ToDo
- * [ ] check every input
- * [ ] refactor
+ * ToDo:
+ * [ ] encapsule module - check inputs
+ * [ ] refactor - chc .h
+ * [ ] dump callback
+ * [ ] rtnl vs nl functions
+ * [ ] stop threads
+ * [ ] change listening
+ * [ ] clean exit - threads, jobs
*/
MODULE_LICENSE( "GPL" );
eth_addr = job->dst_addr;
eth_port = job->dst_port;
rcu_read_unlock();
- printk( KERN_INFO "%x\n", eth_addr );
+ printk( KERN_INFO "%x\n", eth_addr.s_addr );
if( job->src_if_idx == ca.can_ifindex )
gw_udp_send( &cf, eth_addr, eth_port );
}
/* NetLink */
-static int cgw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh,
- void* arg )
+static int cegw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg )
{
struct nlattr* tb[ CGW_MAX+1 ];
- struct rtcanmsg *r;
struct can_eth_gw* cethgw = NULL;
struct eth_can_gw* ecangw = NULL;
int err = 0;
+ /* ToDo: size check
if (nlmsg_len(nlh) < sizeof(*r))
return -EINVAL;
+ */
- r = nlmsg_data(nlh);
- if (r->can_family != AF_CAN)
- return -EPFNOSUPPORT;
-
- err = nlmsg_parse( nlh, sizeof( struct rtcanmsg ), tb, CGW_MAX, NULL );
+ err = nlmsg_parse( nlh, sizeof( struct rtmsg ), tb, CGW_MAX, NULL );
if( err < 0 )
{
printk( KERN_ERR "error: nlmsg_parse\n" );
return err;
}
- switch( r->gwtype )
+ if( tb[CGW_CMD_INFO] == NULL )
+ {
+ printk( "error: bad cmd\n" );
+ return -EINVAL;
+ }
+
+ switch( *(int*)nla_data( tb[CGW_CMD_INFO] ) )
{
- case CGW_TYPE_CONFIG:
+ case CEGW_LISTEN:
listen( 0, *(struct in_addr*)nla_data( tb[CGW_LISTEN_IP] ),
*(u16*)nla_data( tb[CGW_LISTEN_PORT] ) );
break;
return 0;
}
+static int cegw_remove_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg )
+{
+ struct rtmsg* r;
+ struct nlattr* tb[ CGW_MAX+1 ];
+ struct hlist_node* pos,* n;
+ struct can_eth_gw* ceth;
+ struct eth_can_gw* ecan;
+
+ int err = 0;
+
+ if( nlmsg_len(nlh) < sizeof(*r) )
+ return -EINVAL;
+
+ r = nlmsg_data( nlh );
+
+ if( r->rtm_family != AF_CAN )
+ return -EPFNOSUPPORT;
+
+ /*
+ if( r->gwtype != CGW_TYPE_CAN_ETH_UDP )
+ return -EINVAL;
+ */
+ printk( "attrsize=%d\n", nlmsg_attrlen(nlh, sizeof(struct rtmsg)) );
+
+ err = nlmsg_parse( nlh, sizeof(struct rtmsg), tb, CGW_MAX, NULL );
+ if( err != 0 )
+ return -EINVAL;
+
+ if( tb[CGW_CMD_INFO] == NULL )
+ return -EINVAL;
+
+ if( *(int*)nla_data( tb[CGW_CMD_INFO] ) == CEGW_FLUSH )
+ {
+ hlist_for_each_entry_safe( ceth, pos, n, &can_eth_job, list )
+ {
+ hlist_del( &ceth->list );
+ kfree( ceth );
+ }
+ hlist_for_each_entry_safe( ecan, pos, n, ð_can_job, list )
+ {
+ hlist_del( &ecan->list );
+ kfree( ecan );
+ }
+ }
+ // tb[]
+ return 0;
+}
+
+static int cegw_dump_job( struct sk_buff* skb, struct netlink_callback* cb )
+{
+ struct can_eth_gw* ceth;
+ struct eth_can_gw* ecan;
+ struct hlist_node* pos;
+ struct nlmsghdr* nlh;
+ int idx = 0;
+ int s_idx = cb->args[0];
+ int ifidx, type;
+ struct in_addr dst_ip;
+ unsigned short dst_port;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu( ecan, pos, ð_can_job, list )
+ {
+
+ // if( idx < s_idx )
+ // goto cont1;
+
+ nlh = nlmsg_put( skb, 0, 0, 0, 0, 0 );
+
+ ifidx = ecan->dst_if_idx;
+ type = CGW_TYPE_ETH_CAN_UDP;
+ nla_put( skb, CGW_TYPE, sizeof(type), &type );
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(type) );
+
+ nla_put( skb, CGW_CAN_IF, sizeof(ifidx), &ifidx ); /* ToDo return */
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(ifidx) );
+cont1:
+ idx++;
+ }
+ rcu_read_unlock();
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu( ceth, pos, &can_eth_job, list )
+ {
+ // if( idx < s_idx )
+ // goto cont2;
+
+ nlh = nlmsg_put( skb, 0, 0, 0, 0, 0 );
+
+ ifidx = ceth->src_if_idx;
+ type = CGW_TYPE_CAN_ETH_UDP;
+ dst_ip = ceth->dst_addr;
+ dst_port = ceth->dst_port;
+
+ nla_put( skb, CGW_TYPE, sizeof(type), &type );
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(type) );
+
+ nla_put( skb, CGW_CAN_IF, sizeof(ifidx), &ifidx ); /* ToDo return */
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(ifidx) );
+
+ nla_put( skb, CGW_ETH_IP, sizeof(dst_ip), &dst_ip ); /* ToDo return */
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(dst_ip) );
+
+ nla_put( skb, CGW_ETH_PORT, sizeof(dst_port), &dst_port ); /* ToDo return */
+ nlh->nlmsg_len += NLA_HDRLEN + NLA_ALIGN( sizeof(dst_port) );
+
+ //nla_put( skb, CGW_ETH_IP, sizeof() IP_ADDR )
+cont2:
+ idx++;
+ }
+ rcu_read_unlock();
+
+ /* ToDo nlmsg_cancel */
+ cb->args[0] = idx;
+
+ return skb->len;
+}
+
static int listen( int can_ifidx, struct in_addr eth_addr, u16 eth_port )
{
struct sockaddr_in udp_addr;
}
/* subscribe to netlink */
- //if( __rtnl_register( PF_CAN, RTM_GETROUTE, ) != 0 )
- __rtnl_register( PF_CAN, RTM_NEWROUTE, cgw_create_job, NULL, NULL );
+ if( __rtnl_register( PF_CAN, RTM_GETROUTE, NULL, cegw_dump_job, NULL ) != 0 )
+ {
+ printk( KERN_ERR "error: rtnl_register fail\n" );
+ sock_release( udp_sock );
+ sock_release( can_sock );
+ return -1;
+ }
+ __rtnl_register( PF_CAN, RTM_NEWROUTE, cegw_create_job, NULL, NULL );
+ __rtnl_register( PF_CAN, RTM_DELROUTE, cegw_remove_job, NULL, NULL );
//__rtnl_register( PF_CAN, RTM_DELROUTE, )
/*
/* ToDo: stop threads */
}
+ /* ToDo: unregister netlink
+ * free jobs */
printk( "cangw: exit\n" );
//kthread_stop( ts );
}