]> rtime.felk.cvut.cz Git - can-eth-gw.git/blob - utils/cangw/cegw.c
kernel/canethgw accepts configuration over netlink
[can-eth-gw.git] / utils / cangw / cegw.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <libgen.h>
4 #include <string.h>
5 #include <unistd.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 <gw.h>
14
15 /**
16  * ToDo
17  * - refactor error messages
18  * */
19
20 enum {
21         IF_UNDEF,
22         IF_CAN,
23         IF_ETH_UDP
24 };
25
26 int read_addr_port( char* in, struct in_addr* addr, unsigned short* port )
27 {
28         char* delim = NULL;
29         char addrstr[16];
30         int addrlen;
31         
32         if( (delim = strchr( in, ':' )) == NULL )
33         {
34                 fprintf( stderr, "error: ':'\n" );
35                 return -1;
36         }
37
38         /* get address */
39         addrlen = delim - in;
40         memcpy( addrstr, in, addrlen );
41         addrstr[addrlen] = '\0';
42         if( inet_aton( addrstr, addr ) == 0 )
43         {
44                 fprintf( stderr, "error: aton\n" );
45                 return -1;
46         }
47
48         /* get port */
49         if( sscanf( delim, ":%hu", port ) != 1 ) /* todo: handle overflow */
50         {
51                 fprintf( stderr, "error: port\n" );
52                 return -1;
53         }
54
55         return 0;
56 }
57
58 char* read_iftype( char* in, int* iftype )
59 {
60         char* ret = in+4;
61         
62         if( strncmp( "udp@", optarg, 4 ) == 0 )
63         {
64                 *iftype = IF_ETH_UDP;
65                 return ret;
66         }
67         else if( strncmp( "tcp@", optarg, 4 ) == 0 )
68         {
69                 return NULL;
70         }
71         else if( strncmp( "can@", optarg, 4 ) == 0 )
72         {
73                 *iftype = IF_CAN;
74                 return ret;
75         }
76         
77         return NULL;
78 }
79
80 int main( int argc, char* argv[] )
81 {
82         int s;
83         int src_if = 0, dst_if = 0;
84         int can_ifidx = 0;
85         int tmp = 0;
86         int have_listen = 0;
87         struct in_addr eth_addr;
88         unsigned short eth_port;
89         struct in_addr eth_listen_addr;
90         unsigned short eth_listen_port;
91         char* optstr;
92         char opt;
93         struct sockaddr_nl nladdr;
94         int err = 0;
95         
96         struct {
97                 struct nlmsghdr nh;
98                 struct rtcanmsg rtcan;
99                 char buf[600]; /* enough? */
100         } req;
101         
102         while( (opt = getopt( argc, argv, "As:d:l:" )) != -1 )
103         {
104                 switch( opt )
105                 {
106                         case 's':
107                                 if( (optstr = read_iftype( optarg, &src_if )) == NULL )
108                                 {
109                                         fprintf( stderr, "error: bad input format\n" );
110                                         goto syntax_error;
111                                         break;
112                                 }
113                                 
114                                 switch( src_if )
115                                 {
116                                         case IF_CAN:
117                                                 can_ifidx = if_nametoindex( optstr );
118                                                 break;
119                                         case IF_ETH_UDP:
120                                                 read_addr_port( optstr, &eth_addr, &eth_port );
121                                                 break;
122                                         default:
123                                                 fprintf( stderr, "error: unrecognized interface" );
124                                                 goto syntax_error;
125                                                 break;
126                                 }
127                                 break;
128                         case 'd':
129                                 if( (optstr = read_iftype( optarg, &dst_if )) == NULL )
130                                 {
131                                         fprintf( stderr, "error: bad input format\n" );
132                                         goto syntax_error;
133                                         break;
134                                 }
135                                 
136                                 switch( dst_if )
137                                 {
138                                         case IF_CAN:
139                                                 can_ifidx = if_nametoindex( optstr ); /*chk*/
140                                                 break;
141                                         case IF_ETH_UDP:
142                                                 read_addr_port( optstr, &eth_addr, &eth_port ); /*chk*/
143                                                 break;
144                                         default:
145                                                 fprintf( stderr, "error: unrecognized interface" );
146                                                 break;
147                                 }
148                                 break;
149                         case 'l':
150                                 if( (optstr = read_iftype( optarg, &tmp )) == NULL )
151                                 {
152                                         fprintf( stderr, "error: -l bad input format\n" );
153                                         goto syntax_error;
154                                         break;
155                                 }
156                                 
157                                 if( tmp != IF_ETH_UDP )
158                                 {
159                                         fprintf( stderr, "error: -l bad input format\n" );
160                                         goto syntax_error;
161                                         break;
162                                 }
163                                         
164                                 read_addr_port( optstr, &eth_listen_addr, &eth_listen_port ); /*chk*/
165                         default:
166                                 fprintf( stderr, "error: unknown option\n" );
167                         break;
168                 }                               
169         }
170
171         /* 2. do check on arguments */
172         if( (src_if == 0 || dst_if == 0) || (src_if == dst_if) )
173         {
174                 fprintf( stderr, "error: source or destination not specified\n" );
175                 return -1;
176         }
177         
178         if( src_if == dst_if )
179         {
180                 fprintf( stderr, "error: source and destination same interface type\n" );
181         }
182         
183         /* 3. prepare netlink message */
184         req.nh.nlmsg_len   = NLMSG_LENGTH( sizeof(struct rtcanmsg) );
185         req.nh.nlmsg_type  = RTM_NEWROUTE;
186         req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
187         req.nh.nlmsg_seq   = 0;
188         req.nh.nlmsg_pid   = 0; /* ? */
189         
190         req.rtcan.can_family = AF_CAN;
191         req.rtcan.gwtype = (src_if == IF_CAN) ? CGW_TYPE_CAN_ETH_UDP : CGW_TYPE_ETH_CAN_UDP;
192         req.rtcan.flags = 0;
193         
194         addattr_l( &req.nh, sizeof(req), CGW_CAN_IF, &can_ifidx, sizeof(can_ifidx) );
195         switch( req.rtcan.gwtype )
196         {
197                 case CGW_TYPE_CAN_ETH_UDP:
198                         addattr_l( &req.nh, sizeof(req), CGW_ETH_IP, &eth_addr, sizeof(eth_addr) );
199                         addattr_l( &req.nh, sizeof(req), CGW_ETH_PORT, &eth_port, sizeof(eth_port) );
200                         break;
201                 case CGW_TYPE_ETH_CAN_UDP:
202                         break;
203                 default:
204                         break;
205         }
206         
207         if( have_listen )
208         {
209                 addattr_l( &req.nh, sizeof(req), CGW_LISTEN_IP, &eth_listen_addr, sizeof(eth_listen_addr) );
210                 addattr_l( &req.nh, sizeof(req), CGW_LISTEN_PORT, &eth_listen_port, sizeof(eth_listen_port) );
211         }
212         
213         /* 4. send over netlink socket */
214         s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); /* chck */
215         
216         memset(&nladdr, 0, sizeof(nladdr));
217         nladdr.nl_family = AF_NETLINK;
218         nladdr.nl_pid    = 0;
219         nladdr.nl_groups = 0;
220
221         err = sendto( s, &req, req.nh.nlmsg_len, 0, 
222                       (struct sockaddr*)&nladdr, sizeof(nladdr));
223         if (err < 0)
224         {
225                 perror( "netlink sendto" );
226                 return err;
227         }
228         
229         /* ack? */
230         
231         return 0;
232 syntax_error:
233         return -1;
234 }