]> rtime.felk.cvut.cz Git - can-eth-gw.git/blob - utils/cegw/cegw.c
set udp listening address
[can-eth-gw.git] / utils / cegw / cegw.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <libgen.h>
4 #include <string.h>
5 #include <getopt.h>
6 #include <errno.h>
7 #include <sys/socket.h>
8 #include <net/if.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>
15 #include "canethgw.h"
16
17 /**
18  * ToDo
19  * [ ] refactor error messages
20  * [ ] start/stop listening
21  * [ ] remove routing job
22  * [ ] recv netlink reponse
23  * 
24  */
25
26 #define CMD_STOP_LISTEN    1
27 #define CMD_START_LISTEN   2
28 #define CMD_ADD_RULE       4
29
30 enum {
31         IF_UNDEF,
32         IF_CAN,
33         IF_ETH_UDP
34 };
35
36
37 /**
38  * parses @in for eth address, valid input is 
39  * e.g. udp@127.0.0.1:10502 or can@vcan0
40  *
41  * @param[out] addr ip address
42  * @param[out] port transport layer port
43  * @return 0 on success
44  */
45 int read_addr_port( char* in, struct in_addr* addr, unsigned short* port )
46 {
47         char* delim = NULL;
48         char addrstr[16];
49         int addrlen;
50         
51         if( (delim = strchr( in, ':' )) == NULL )
52         {
53                 fprintf( stderr, "error: ':'\n" );
54                 return -1;
55         }
56
57         /* get address */
58         addrlen = delim - in;
59         memcpy( addrstr, in, addrlen );
60         addrstr[addrlen] = '\0';
61         if( inet_aton( addrstr, addr ) == 0 )
62         {
63                 fprintf( stderr, "error: aton\n" );
64                 return -1;
65         }
66
67         /* get port */
68         if( sscanf( delim, ":%hu", port ) != 1 ) /* todo: handle overflow */
69         {
70                 fprintf( stderr, "error: port\n" );
71                 return -1;
72         }
73
74         return 0;
75 }
76
77 char* read_iftype( char* in, int* iftype )
78 {
79         char* ret = in+4;
80         
81         if( strncmp( "udp@", optarg, 4 ) == 0 )
82         {
83                 *iftype = IF_ETH_UDP;
84                 return ret;
85         }
86         else if( strncmp( "tcp@", optarg, 4 ) == 0 )
87         {
88                 return NULL;
89         }
90         else if( strncmp( "can@", optarg, 4 ) == 0 )
91         {
92                 *iftype = IF_CAN;
93                 return ret;
94         }
95         
96         return NULL;
97 }
98
99 int main( int argc, char* argv[] )
100 {
101         int s;
102         int src_if = 0, dst_if = 0;
103         int can_ifidx = 0;
104         int tmp = 0;
105         int cmd = 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;
110         char* optstr;
111         char opt;
112         struct sockaddr_nl nladdr;
113         int err = 0;
114
115         struct option long_opt[] =
116         {
117                 { "start-listen", 1, NULL, 'l' },
118                 { "stop-listen" , 1, NULL, 'k' },
119                 { 0, 0, 0, 0 }
120         };
121         
122         struct {
123                 struct nlmsghdr nh;
124                 struct rtcanmsg rtcan;
125                 char buf[600]; /* enough? */
126         } req;
127         
128         while( 1 )
129         {
130                 opt = getopt_long( argc, argv, "As:d:", long_opt, NULL );
131                 if( opt == -1 )
132                         break;
133
134                 switch( opt )
135                 {
136                         case 's':
137                                 cmd |= CMD_ADD_RULE;
138                                 if( (optstr = read_iftype( optarg, &src_if )) == NULL )
139                                 {
140                                         fprintf( stderr, "error: bad input format\n" );
141                                         goto syntax_error;
142                                         break;
143                                 }
144                                 
145                                 switch( src_if )
146                                 {
147                                         case IF_CAN:
148                                                 can_ifidx = if_nametoindex( optstr );
149                                                 break;
150                                         case IF_ETH_UDP:
151                                                 read_addr_port( optstr, &eth_addr, &eth_port );
152                                                 break;
153                                         default:
154                                                 fprintf( stderr, "error: unrecognized interface" );
155                                                 goto syntax_error;
156                                                 break;
157                                 }
158                                 break;
159                         case 'd':
160                                 cmd |= CMD_ADD_RULE;
161                                 if( (optstr = read_iftype( optarg, &dst_if )) == NULL )
162                                 {
163                                         fprintf( stderr, "error: bad input format\n" );
164                                         goto syntax_error;
165                                         break;
166                                 }
167                                 
168                                 switch( dst_if )
169                                 {
170                                         case IF_CAN:
171                                                 can_ifidx = if_nametoindex( optstr ); /*chk*/
172                                                 break;
173                                         case IF_ETH_UDP:
174                                                 read_addr_port( optstr, &eth_addr, &eth_port ); /*chk*/
175                                                 break;
176                                         default:
177                                                 fprintf( stderr, "error: unrecognized interface" );
178                                                 break;
179                                 }
180                                 break;
181                         case 'l':
182                                 cmd |= CMD_START_LISTEN;
183                                 if( (optstr = read_iftype( optarg, &tmp )) == NULL )
184                                 {
185                                         fprintf( stderr, "error: -l bad input format\n" );
186                                         goto syntax_error;
187                                         break;
188                                 }
189                                 
190                                 if( tmp != IF_ETH_UDP )
191                                 {
192                                         fprintf( stderr, "error: -l bad input format\n" );
193                                         goto syntax_error;
194                                         break;
195                                 }
196                                         
197                                 read_addr_port( optstr, &eth_listen_addr, &eth_listen_port ); /*chk*/
198                         case 'k':
199                                 cmd |= CMD_STOP_LISTEN;
200                                 break;
201                         case '?':
202                                 break;
203                         default:
204                                 fprintf( stderr, "error: unknown option\n" );
205                         break;
206                 }                               
207         }
208
209         /* 2. do check on arguments */
210         if( cmd & CMD_ADD_RULE )
211         {
212                 if( (src_if == 0 || dst_if == 0) || (src_if == dst_if) )
213                 {
214                         fprintf( stderr, "error: source or destination not specified\n" );
215                         return -1;
216                 }
217         
218                 if( src_if == dst_if )
219                 {
220                         fprintf( stderr, "error: source and destination same interface type\n" );
221                 }
222         }
223         
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; /* ? */
230         
231         req.rtcan.can_family = AF_CAN;
232         req.rtcan.flags = 0;
233
234         if( cmd & CMD_ADD_RULE )
235         {
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 )
239                 {
240                         case CGW_TYPE_CAN_ETH_UDP:
241                                 addattr_l( &req.nh, sizeof(req), CGW_ETH_IP, &eth_addr, sizeof(eth_addr) );
242                                 addattr_l( &req.nh, sizeof(req), CGW_ETH_PORT, &eth_port, sizeof(eth_port) );
243                                 break;
244                         case CGW_TYPE_ETH_CAN_UDP:
245                                 break;
246                         default:
247                                 break;
248                 }
249         }
250         
251         if( cmd & CMD_START_LISTEN )
252         {
253                 req.rtcan.gwtype = CGW_TYPE_CONFIG;
254                 addattr_l( &req.nh, sizeof(req), CGW_LISTEN_IP, &eth_listen_addr, sizeof(eth_listen_addr) );
255                 addattr_l( &req.nh, sizeof(req), CGW_LISTEN_PORT, &eth_listen_port, sizeof(eth_listen_port) );
256                 printf( "start listen: %x, %hu\n", eth_listen_addr, eth_listen_port );
257         }
258         
259         /* 4. send over netlink socket */
260         s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); /* chck */
261         
262         memset(&nladdr, 0, sizeof(nladdr));
263         nladdr.nl_family = AF_NETLINK;
264         nladdr.nl_pid    = 0;
265         nladdr.nl_groups = 0;
266
267         err = sendto( s, &req, req.nh.nlmsg_len, 0, 
268                       (struct sockaddr*)&nladdr, sizeof(nladdr));
269         if (err < 0)
270         {
271                 perror( "netlink sendto" );
272                 return err;
273         }
274         
275         /* ack? */
276         
277         return 0;
278 syntax_error:
279         return -1;
280 }
281