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>
20 * [ ] refactor error messages
21 * [ ] start/stop listening
22 * [ ] remove routing job
23 * [ ] recv netlink reponse
27 #define CEGW_CMD_ADD 1
28 #define CEGW_CMD_LIST 2
29 #define CEGW_CMD_FLUSH 4
30 #define CEGW_CMD_LISTEN 8
44 struct in_addr eth_addr;
45 unsigned short eth_port;
46 struct in_addr eth_listen_addr;
47 unsigned short eth_listen_port;
54 char buf[768]; /* enough? */
57 unsigned int cegw_errno = 0;
67 char* cegw_errlist[] =
69 [ CEGW_ERR_UNKNOWN ] = "unknown error",
70 [ CEGW_ERR_IF_UNSPEC ] = "source or destination not specified",
71 [ CEGW_ERR_IF_SAME ] = "source and destination have same interface type",
72 [ CEGW_ERR_IF_TYPE ] = "unknown interface type"
75 static void perr( char* s )
79 fprintf( stderr, "error: %s; %s\n", s,
80 cegw_errlist[ cegw_errno ] );
84 fprintf( stderr, "error: %s\n", cegw_errlist[ cegw_errno ] );
88 * Parses @in for eth address. Valid input is
89 * e.g. udp@127.0.0.1:10502 or can@vcan0.
91 * @param[out] addr ip address
92 * @param[out] port transport layer port
93 * @return 0 on success
95 int read_addr_port( char* in, struct in_addr* addr, unsigned short* port )
101 if( (delim = strchr( in, ':' )) == NULL )
103 fprintf( stderr, "error: ':'\n" );
108 addrlen = delim - in;
109 memcpy( addrstr, in, addrlen );
110 addrstr[addrlen] = '\0';
111 if( inet_aton( addrstr, addr ) == 0 )
113 fprintf( stderr, "error: aton\n" );
118 if( sscanf( delim, ":%hu", port ) != 1 ) /* todo: handle overflow */
120 fprintf( stderr, "error: port\n" );
128 * Reads @in for iftype (e.g. "can@" or "udp@").
130 * @param[in] in string to search in
131 * @param[out] iftype iftype detected
132 * @return pointer to @in after iftype on success, NULL otherwise
134 char* read_iftype( char* in, int* iftype )
138 if( strncmp( "udp@", optarg, 4 ) == 0 )
140 *iftype = IF_ETH_UDP;
144 else if( strncmp( "tcp@", optarg, 4 ) == 0 )
149 else if( strncmp( "can@", optarg, 4 ) == 0 )
155 errno = CEGW_ERR_IF_TYPE;
159 int read_if( char* in, int* iftype, struct cegw_data* d )
163 if( (optstr = read_iftype( in, iftype )) == NULL )
171 d->can_ifidx = if_nametoindex( optstr );
174 read_addr_port( optstr, &d->eth_addr, &d->eth_port );
184 inline static int cegw_add( struct cegw_nlmsg* req, struct cegw_data* d )
188 req->nh.nlmsg_type = RTM_NEWROUTE;
189 if( (d->src_if == 0 || d->dst_if == 0) )
191 cegw_errno = CEGW_ERR_IF_UNSPEC;
195 if( d->src_if == d->dst_if )
197 cegw_errno = CEGW_ERR_IF_SAME;
201 gwtype = (d->src_if == IF_CAN) ? CGW_TYPE_CAN_ETH_UDP : CGW_TYPE_ETH_CAN_UDP;
202 addattr_l( &req->nh, sizeof(*req), CGW_CAN_IF, &d->can_ifidx, sizeof(d->can_ifidx) );
206 case CGW_TYPE_CAN_ETH_UDP:
207 addattr_l( &req->nh, sizeof(*req), CGW_ETH_IP, &d->eth_addr, sizeof(d->eth_addr) );
208 addattr_l( &req->nh, sizeof(*req), CGW_ETH_PORT, &d->eth_port, sizeof(d->eth_port) );
210 case CGW_TYPE_ETH_CAN_UDP:
216 addattr32( &req->nh, sizeof(*req), CGW_CMD_INFO, gwtype );
221 inline static int cegw_listen( struct cegw_nlmsg* req, struct cegw_data* d )
223 req->nh.nlmsg_type = RTM_NEWROUTE;
224 addattr32( &req->nh, sizeof(*req), CGW_CMD_INFO, CEGW_LISTEN );
225 addattr_l( &req->nh, sizeof(*req), CGW_LISTEN_IP, &d->eth_listen_addr, sizeof(d->eth_listen_addr) );
226 addattr_l( &req->nh, sizeof(*req), CGW_LISTEN_PORT, &d->eth_listen_port, sizeof(d->eth_listen_port) );
227 printf( "start listen: %x, %hu\n", d->eth_listen_addr, d->eth_listen_port );
232 inline static int cegw_list( struct cegw_nlmsg* req, struct cegw_data* d )
237 inline static int cegw_flush( struct cegw_nlmsg* req, struct cegw_data* d )
240 addattr32( &req->nh, sizeof(*req), CGW_CMD_INFO, CEGW_FLUSH );
241 req->nh.nlmsg_type = RTM_DELROUTE;
242 // addattr_l( &req->nh, sizeof(*req), 0, &foo, sizeof(foo) );
243 //addattr_l( &req->nh, sizeof(*req), CGW_CAN_IF, &d->can_ifidx, sizeof(d->can_ifidx) );
244 // req->rtcan.gwtype = CGW_TYPE_CAN_ETH_UDP;
245 // req->rtcan.flags = 5;//CEGW_FLUSH;
249 int main( int argc, char* argv[] )
256 struct sockaddr_nl nladdr;
258 struct cegw_nlmsg req;
260 char rxbuf[256]; /* 8129+ ? */
262 struct nlmsghdr* nlh;
263 struct nlmsgerr* rte;
265 printf( "size=%d\n", NLMSG_LENGTH(sizeof(struct rtmsg)) );
267 memset( &d, 0, sizeof(d) );
269 struct option long_opt[] =
271 { "add" , 0, NULL, 'A' },
272 { "flush" , 0, NULL, 'F' },
273 { "list" , 0, NULL, 'L' },
274 { "listen", 1, NULL, 'l' },
280 opt = getopt_long( argc, argv, "As:d:", long_opt, NULL );
290 cmd |= CEGW_CMD_FLUSH;
293 cmd |= CEGW_CMD_FLUSH;
296 cmd |= CEGW_CMD_LISTEN;
297 if( (optstr = read_iftype( optarg, &tmp )) == NULL )
302 if( tmp != IF_ETH_UDP )
304 fprintf( stderr, "error: -l bad input format\n" );
307 read_addr_port( optstr, &d.eth_listen_addr, &d.eth_listen_port ); /*chk*/
310 if( read_if( optarg, &d.src_if, &d ) != 0 )
312 fprintf( stderr, "error: bad input format\n" );
318 if( read_if( optarg, &d.dst_if, &d ) != 0 )
320 fprintf( stderr, "error: bad input format\n" );
326 fprintf( stderr, "error: unknown option\n" );
330 fprintf( stderr, "error: unknown option\n" );
336 /* prepare netlink message */
337 req.nh.nlmsg_len = NLMSG_LENGTH( sizeof(struct rtmsg) );
338 req.nh.nlmsg_type = RTM_DELROUTE;
339 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
340 req.nh.nlmsg_seq = 0;
341 req.nh.nlmsg_pid = 0; /* ? */
343 memset( &req.rt, 0, sizeof(req.rt) );
344 req.rt.rtm_family = AF_CAN;
346 //req.rt.gwtype = CGW_TYPE_CAN_CAN;
352 fprintf( stderr, "error: command not specified\n" );
355 if( cegw_add( &req, &d ) != 0 )
362 cegw_flush( &req, &d );
365 cegw_list( &req, &d );
367 case CEGW_CMD_LISTEN:
368 cegw_listen( &req, &d );
371 fprintf( stderr, "error: command mismatch\n" );
375 /* send over netlink socket */
376 s = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); /* chck */
378 memset( &nladdr, 0, sizeof(nladdr) );
379 nladdr.nl_family = AF_NETLINK;
382 nladdr.nl_groups = 0;
384 err = sendto( s, &req, req.nh.nlmsg_len, 0,
385 (struct sockaddr*)&nladdr, sizeof(nladdr) );
388 perror( "netlink sendto" );
393 rsize = recv( s, &rxbuf, sizeof(rxbuf), 0 );
396 fprintf( stderr, "error: recv\n" );
399 nlh = (struct nlmsghdr*)rxbuf;
400 if( nlh->nlmsg_type != NLMSG_ERROR )
402 fprintf( stderr, "error: unexpected netlink answer=%d\n", nlh->nlmsg_type );
405 rte = (struct nlmsgerr*)NLMSG_DATA( nlh );
408 fprintf( stderr, "error: netlink(%d); %s\n", err, strerror(abs(err)) );