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