]> rtime.felk.cvut.cz Git - can-eth-gw.git/blob - utils/cegw/cegw.c
authors and license information added
[can-eth-gw.git] / utils / cegw / cegw.c
1 /*
2  * Copyright: (c) 2012 Czech Technical University in Prague
3  *
4  * Authors:
5  *      Radek Matějka <radek.matejka@gmail.com>
6  *      Michal Sojka  <sojkam1@fel.cvut.cz>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version
11  * 2 of the License, or (at your option) any later version.
12  */
13
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/socket.h>
19 #include <net/if.h>
20 #include <arpa/inet.h>
21 #include <linux/can.h>
22 #include <limits.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <sys/ioctl.h>
26 #include "canethgw.h"
27
28 unsigned int cegw_errno = 0;
29
30 enum
31 {
32         CEGW_ERR_UNKNOWN,
33         CEGW_ERR_COLON,
34         CEGW_ERR_UNEXLEN,
35         CEGW_ERR_ATON,
36         CEGW_ERR_PORT
37 };
38
39 char* cegw_errlist[] =
40 {
41         [CEGW_ERR_UNKNOWN] = "",
42         [CEGW_ERR_COLON  ] = "expected ':' (<ip>:<port>)",
43         [CEGW_ERR_UNEXLEN] = "unexpected ip address length, please use dot notation"
44                              " (eg. 127.0.0.1)",
45         [CEGW_ERR_ATON   ] = "ip address mismatch",
46         [CEGW_ERR_PORT   ] = "port number"
47 };
48
49 static const char help_msg[] = "usage:\n"
50                                "        %s <can_if> <udp_listen_addr>:<port> <udp_dest_addr>:<port>\n"
51                                "                [list of additional udp recipients <addr:port>]\n"
52                                "example:\n"
53                                "        %s can0 192.168.0.1:10501 192.168.0.4:980 192.168.0.7:1160\n\n"
54                                "        Executing this command will set the gateway so that it will\n"
55                                "        listen for udp messages on 192.168.0.1:10501 and send them\n"
56                                "        to can0. Simultaneously, it will send all messages from can0\n"
57                                "        to 192.168.0.4:980 and 192.168.0.7:1160 via udp. The message is\n"
58                                "        therefore cloned. Notice that there can be any number\n"
59                                "        of udp recipients.\n";
60
61 static void perr(char* s)
62 {
63         if (s) {
64                 if (cegw_errno == 0) {
65                         fprintf(stderr, "error: %s\n", s);
66
67                 } else {
68                         fprintf(stderr, "error: %s, %s\n", s, cegw_errlist[cegw_errno]);
69                 }
70                 return;
71         }
72
73         fprintf(stderr, "error: %s\n", cegw_errlist[cegw_errno]);
74 }
75
76 /**
77  * read_addrport - parses @in for eth address.
78  * Valid input is e.g. 127.0.0.1:10502. If parsing fails
79  * the cause is stored in cegw_errno.
80  *
81  * @param[in]  in   string to search in
82  * @param[out] addr ip address
83  * @param[out] port transport layer port
84  * @return 0 on success, -1 otherwise
85  */
86 int read_addrport(char* in, struct in_addr* addr, unsigned short* port)
87 {
88         char* delim = NULL;
89         const int addrstr_len = 16;
90         char addrstr[addrstr_len];
91         int addrlen;
92
93         if ((delim = strchr(in, ':')) == NULL) {
94                 cegw_errno = CEGW_ERR_COLON;
95                 return -1;
96         }
97
98         /* get address */
99         addrlen = delim - in;
100         if (addrlen > addrstr_len) {
101                 cegw_errno = CEGW_ERR_UNEXLEN;
102                 return -1;
103         }
104
105         memcpy(addrstr, in, addrlen);
106         addrstr[addrlen] = '\0';
107         if (inet_aton(addrstr, addr) == 0) {
108                 cegw_errno = CEGW_ERR_ATON;
109                 return -1;
110         }
111
112         /* get port */
113         /* ToDo: handle overflow */
114         if (sscanf(delim, ":%hu", port) != 1) {
115                 cegw_errno = CEGW_ERR_PORT;
116                 return -1;
117         }
118
119         return 0;
120 }
121
122 int main(int argc, char* argv[])
123 {
124         int i;
125         int fd;
126         int tmpi;
127         int dstcnt;
128         unsigned short port;
129         int udp_sock, can_sock;
130         struct sockaddr_in udp_addr;
131         struct sockaddr_can can_addr;
132         struct sockaddr_in* dst = NULL;
133         struct cegw_ioctl* gwctl = NULL;
134
135         if (argc == 1)
136         {
137                 printf(help_msg, argv[0], argv[0]);
138                 return 0;
139         }
140
141         if (argc < 4) {
142                 perr("not enought arguments");
143                 printf(help_msg, argv[0], argv[0]);
144                 /* ToDo: print usage */
145                 return -1;
146         }
147
148         dstcnt = argc-3;
149         gwctl = (struct cegw_ioctl*)malloc(sizeof(*gwctl) + (dstcnt)*sizeof(struct sockaddr_in));
150
151         for (i=1; i<argc; i++) {
152                 switch (i) {
153                         case 1: /* can ifindex */
154                                 can_addr.can_family = AF_CAN;
155                                 tmpi = if_nametoindex(argv[i]);
156                                 if (tmpi == 0) {
157                                         perr("given can interface not found");
158                                         free(gwctl);
159                                         return -1;
160                                 }
161                                 can_addr.can_ifindex = tmpi;
162                                 break;
163                         case 2: /* listen addr */
164                                 udp_addr.sin_family = AF_INET;
165                                 if (read_addrport(argv[i], &udp_addr.sin_addr, &port) != 0) {
166                                         perr("listening address mismatch");
167                                         free(gwctl);
168                                         return -1;
169                                 }
170                                 udp_addr.sin_port = htons(port);
171                                 break;
172                         default: /* udp destination */
173                                 dst = &gwctl->udp_dst[i-3];
174                                 dst->sin_family = AF_INET;
175                                 if (read_addrport(argv[i], &dst->sin_addr, &port) != 0) {
176                                         perr("udp destination mismatch");
177                                         free(gwctl);
178                                         return -1;
179                                 }
180                                 dst->sin_port = htons(port);
181                                 break;
182                 }
183         }
184
185         /* prepare udp socket */
186         udp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
187         if (udp_sock == -1) {
188                 fprintf(stderr, "error: udp socket(..) failed\n");
189                 free(gwctl);
190                 return -1;
191         }
192
193         if (bind(udp_sock, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr_in)) != 0) {
194                 fprintf(stderr, "error: udp bind(..) failed\n");
195                 free(gwctl);
196                 return -1;
197         }
198
199         /* prepare can socket */
200         can_sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
201         if (can_sock == -1) {
202                 fprintf(stderr, "error: can socket(..) failed\n");
203                 free(gwctl);
204                 return -1;
205         }
206
207         if (bind(can_sock, (struct sockaddr *)&can_addr, sizeof(struct sockaddr_can)) != 0) {
208                 fprintf(stderr, "error: can bind(..) failed\n");
209                 free(gwctl);
210                 return -1;
211         }
212
213         /* send it to kernel gateway */
214         fd = open("/dev/cegw", O_RDONLY);
215         if (fd == -1) {
216                 fprintf(stderr, "error: could not open device file\n");
217                 free(gwctl);
218                 return -1;
219         }
220
221         gwctl->can_sock = can_sock;
222         gwctl->udp_sock = udp_sock;
223         gwctl->udp_dstcnt = dstcnt;
224         gwctl->udp_addrlen = sizeof(struct sockaddr_in);
225
226         if (ioctl(fd, CEGW_IOCTL_START, gwctl) != 0) {
227                 perror(NULL);
228                 free(gwctl);
229                 return -1;
230         }
231         printf("gateway successfully set and running\n");
232         free(gwctl);
233
234         /* sleep until someone kills me */
235         while (1) {
236                 sleep(UINT_MAX);
237         }
238
239         return 0;
240 }
241