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