7 #include <sys/socket.h>
9 #include <libnetlink.h>
10 #include <linux/netlink.h>
11 #include <linux/rtnetlink.h>
12 #include <arpa/inet.h>
13 #include <linux/can.h>
14 #include <linux/types.h>
19 * [ ] refactor error messages
20 * [ ] start/stop listening
21 * [ ] remove routing job
22 * [ ] recv netlink reponse
26 #define CMD_STOP_LISTEN 1
27 #define CMD_START_LISTEN 2
28 #define CMD_ADD_RULE 4
38 * parses @in for eth address, valid input is
39 * e.g. udp@127.0.0.1:10502 or can@vcan0
41 * @param[out] addr ip address
42 * @param[out] port transport layer port
43 * @return 0 on success
45 int read_addr_port( char* in, struct in_addr* addr, unsigned short* port )
51 if( (delim = strchr( in, ':' )) == NULL )
53 fprintf( stderr, "error: ':'\n" );
59 memcpy( addrstr, in, addrlen );
60 addrstr[addrlen] = '\0';
61 if( inet_aton( addrstr, addr ) == 0 )
63 fprintf( stderr, "error: aton\n" );
68 if( sscanf( delim, ":%hu", port ) != 1 ) /* todo: handle overflow */
70 fprintf( stderr, "error: port\n" );
77 char* read_iftype( char* in, int* iftype )
81 if( strncmp( "udp@", optarg, 4 ) == 0 )
86 else if( strncmp( "tcp@", optarg, 4 ) == 0 )
90 else if( strncmp( "can@", optarg, 4 ) == 0 )
99 int main( int argc, char* argv[] )
102 int src_if = 0, dst_if = 0;
106 struct in_addr eth_addr;
107 unsigned short eth_port;
108 struct in_addr eth_listen_addr;
109 unsigned short eth_listen_port;
112 struct sockaddr_nl nladdr;
115 struct option long_opt[] =
117 { "start-listen", 1, NULL, 'l' },
118 { "stop-listen" , 1, NULL, 'k' },
124 struct rtcanmsg rtcan;
125 char buf[600]; /* enough? */
130 opt = getopt_long( argc, argv, "As:d:", long_opt, NULL );
138 if( (optstr = read_iftype( optarg, &src_if )) == NULL )
140 fprintf( stderr, "error: bad input format\n" );
148 can_ifidx = if_nametoindex( optstr );
151 read_addr_port( optstr, ð_addr, ð_port );
154 fprintf( stderr, "error: unrecognized interface" );
161 if( (optstr = read_iftype( optarg, &dst_if )) == NULL )
163 fprintf( stderr, "error: bad input format\n" );
171 can_ifidx = if_nametoindex( optstr ); /*chk*/
174 read_addr_port( optstr, ð_addr, ð_port ); /*chk*/
177 fprintf( stderr, "error: unrecognized interface" );
182 cmd |= CMD_START_LISTEN;
183 if( (optstr = read_iftype( optarg, &tmp )) == NULL )
185 fprintf( stderr, "error: -l bad input format\n" );
190 if( tmp != IF_ETH_UDP )
192 fprintf( stderr, "error: -l bad input format\n" );
197 read_addr_port( optstr, ð_listen_addr, ð_listen_port ); /*chk*/
199 cmd |= CMD_STOP_LISTEN;
204 fprintf( stderr, "error: unknown option\n" );
209 /* 2. do check on arguments */
210 if( cmd & CMD_ADD_RULE )
212 if( (src_if == 0 || dst_if == 0) || (src_if == dst_if) )
214 fprintf( stderr, "error: source or destination not specified\n" );
218 if( src_if == dst_if )
220 fprintf( stderr, "error: source and destination same interface type\n" );
224 /* 3. prepare netlink message */
225 req.nh.nlmsg_len = NLMSG_LENGTH( sizeof(struct rtcanmsg) );
226 req.nh.nlmsg_type = RTM_NEWROUTE;
227 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
228 req.nh.nlmsg_seq = 0;
229 req.nh.nlmsg_pid = 0; /* ? */
231 req.rtcan.can_family = AF_CAN;
234 if( cmd & CMD_ADD_RULE )
236 req.rtcan.gwtype = (src_if == IF_CAN) ? CGW_TYPE_CAN_ETH_UDP : CGW_TYPE_ETH_CAN_UDP;
237 addattr_l( &req.nh, sizeof(req), CGW_CAN_IF, &can_ifidx, sizeof(can_ifidx) );
238 switch( req.rtcan.gwtype )
240 case CGW_TYPE_CAN_ETH_UDP:
241 addattr_l( &req.nh, sizeof(req), CGW_ETH_IP, ð_addr, sizeof(eth_addr) );
242 addattr_l( &req.nh, sizeof(req), CGW_ETH_PORT, ð_port, sizeof(eth_port) );
244 case CGW_TYPE_ETH_CAN_UDP:
251 if( cmd & CMD_START_LISTEN )
253 req.rtcan.gwtype = CGW_TYPE_CONFIG;
254 addattr_l( &req.nh, sizeof(req), CGW_LISTEN_IP, ð_listen_addr, sizeof(eth_listen_addr) );
255 addattr_l( &req.nh, sizeof(req), CGW_LISTEN_PORT, ð_listen_port, sizeof(eth_listen_port) );
256 printf( "start listen: %x, %hu\n", eth_listen_addr, eth_listen_port );
259 /* 4. send over netlink socket */
260 s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); /* chck */
262 memset(&nladdr, 0, sizeof(nladdr));
263 nladdr.nl_family = AF_NETLINK;
265 nladdr.nl_groups = 0;
267 err = sendto( s, &req, req.nh.nlmsg_len, 0,
268 (struct sockaddr*)&nladdr, sizeof(nladdr));
271 perror( "netlink sendto" );