blob: a850de8deaa7c5ebb3d7eb0dbe1fe09e5a2166c5 [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002 Mondru AB.
4 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
10 * The initial developer of the original code is
11 * Jens Jakobsen <jj@openggsn.org>
12 *
13 * Contributor(s):
14 *
15 */
16
17/* ggsn.c
18 *
19 */
20
21#ifdef __linux__
22#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
23#endif
24
25
26#include <syslog.h>
27#include <ctype.h>
28#include <netdb.h>
29#include <signal.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <sys/wait.h>
38#include <sys/stat.h>
39#include <unistd.h>
40
41#include <sys/socket.h>
42#include <sys/ioctl.h>
43#include <net/if.h>
44#include <features.h>
45
46#include <errno.h>
47
48#include <asm/types.h>
49#include <sys/socket.h>
50#include <linux/netlink.h>
51
52#include <time.h>
53
54#include "tun.h"
55#include "../gtp/pdp.h"
56#include "../gtp/gtp.h"
57#include "cmdline.h"
58
59
60int maxfd = 0; /* For select() */
61int tun_fd = -1; /* Network file descriptor */
62struct tun_t *tun; /* TUN instance */
63struct in_addr net, mask; /* Network interface */
64int debug; /* Print debug output */
65
66
67/* Used to write process ID to file. Assume someone else will delete */
68void log_pid(char *pidfile) {
69 FILE *file;
70 mode_t oldmask;
71
72 oldmask = umask(022);
73 file = fopen(pidfile, "w");
74 umask(oldmask);
75 if(!file)
76 return;
77 fprintf(file, "%d\n", getpid());
78 fclose(file);
79}
80
81
82int encaps_printf(void *p, void *packet, unsigned len)
83{
84 int i;
85 if (debug) {
86 printf("The packet looks like this:\n");
87 for( i=0; i<len; i++) {
88 printf("%02x ", (unsigned char)*(char *)(packet+i));
89 if (!((i+1)%16)) printf("\n");
90 };
91 printf("\n");
92 }
93 return 0;
94}
95
96int getip(struct pdp_t *pdp, void* ipif, struct ul66_t *eua,
97 struct in_addr *net, struct in_addr *mask) {
98 struct in_addr addr;
99 uint32_t ip_start, ip_end, ip_cur;
100 struct pdp_t *pdp_;
101 struct ul66_t eua_;
102
103 if (debug) {
104 printf("Begin getip %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
105 eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
106 }
107
108 ip_start = ntoh32(net->s_addr & mask->s_addr);
109 ip_end = ntoh32(hton32(ip_start) | ~mask->s_addr);
110
111 /* By convention the first address is the network address, and the last */
112 /* address is the broadcast address. This way two IP addresses are "lost" */
113 ip_start++;
114
115 if (eua->l == 0) { /* No address supplied. Find one that is available! */
116 /* This routine does linear search. In order to support millions of
117 * addresses we should instead keep a linked list of available adresses */
118 for (ip_cur = ip_start; ip_cur < ip_end; ip_cur++) {
119 addr.s_addr = hton32(ip_cur);
120 pdp_ntoeua(&addr, &eua_);
121 if (pdp_ipget(&pdp_, ipif, &eua_) == -1) {
122 pdp_ntoeua(&addr, &pdp->eua);
123 pdp->ipif = ipif;
124 return 0;
125 };
126 }
127 return EOF; /* No addresses available */
128 }
129 else { /* Address supplied */
130 if (pdp_ipget(&pdp_, ipif, eua) == -1) {
131 pdp->ipif = ipif;
132 pdp->eua.l = eua->l;
133 memcpy(pdp->eua.v, eua->v, eua->l);
134 return 0;
135 }
136 else return EOF; /* Specified address not available */
137 }
138}
139
140
141int delete_context(struct pdp_t *pdp) {
142 pdp_ipdel(pdp);
143 return 0;
144}
145
146
147
148int create_context(struct pdp_t *pdp) {
149
150 if (debug) printf("Received create PDP context request\n");
151
152 pdp->eua.l=0; /* TODO: Indicates dynamic IP */
153
154 /* ulcpy(&pdp->qos_neg, &pdp->qos_req, sizeof(pdp->qos_req.v)); */
155 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_neg));
156
157 getip(pdp, tun, &pdp->eua, &net, &mask);
158 pdp_ipset(pdp, pdp->ipif, &pdp->eua);
159
160 return 0; /* Success */
161}
162
163
164
165int create_tun() {
166 char buf[1024];
167 char snet[100], smask[100];
168
169 if ((tun_fd = tun_newtun((struct tun_t**) &tun)) > maxfd)
170 maxfd = tun_fd;
171
172 if (tun_fd == -1) {
173 printf("Failed to open tun\n");
174 exit(1);
175 }
176
177 strncpy(snet, inet_ntoa(net), 100);
178 strncpy(smask, inet_ntoa(mask), 100);
179
180 sprintf(buf, "ifconfig %s %s mtu 1450 netmask %s",
181 tun->devname, snet, smask);
182 if (debug) printf("%s\n", buf);
183 system(buf);
184
185 system("echo 1 > /proc/sys/net/ipv4/ip_forward");
186
187 return 0;
188}
189
190
191int encaps_gtp(void *gsn, struct tun_t *tun, void *pack, unsigned len) {
192 struct pdp_t *pdp;
193 struct in_addr addr;
194 struct ul66_t eua;
195 /*printf("encaps_gtp. Packet received: forwarding to gtp.\n");*/
196 /* First we need to extract the IP destination address */
197 memcpy(&addr.s_addr, pack+16, 4); /* This ought to be dest addr */
198 pdp_ntoeua(&addr, &eua);
199 if (pdp_ipget(&pdp, tun, &eua) == 0) {
200 return gtp_gpdu((struct gsn_t*) gsn, pdp, pack, len);
201 }
202 else {
203 if (debug) printf("Received packet with no destination!!!\n");
204 return 0;
205 }
206}
207
208
209int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
210 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
211 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
212}
213
214
215int main(int argc, char **argv)
216{
217 /* gengeopt declarations */
218 struct gengetopt_args_info args_info;
219
220 struct hostent *host;
221
222 struct in_addr listen;
223
224 int gtpfd = -1; /* Network file descriptor */
225 struct gsn_t *gsn; /* GSN instance */
226
227 fd_set fds; /* For select() */
228 struct timeval idleTime; /* How long to select() */
229 int i; /* for loop */
230
231 struct ul_t qos, apn;
232 unsigned char qosh[3], apnh[256];
233
234 int timelimit; /* Number of seconds to be connected */
235 int starttime; /* Time program was started */
236
237 /* open a connection to the syslog daemon */
238 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
239 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
240
241 if (cmdline_parser (argc, argv, &args_info) != 0)
242 exit(1);
243 if (args_info.debug_flag) {
244 printf("listen: %s\n", args_info.listen_arg);
245 printf("conf: %s\n", args_info.conf_arg);
246 printf("fg: %d\n", args_info.fg_flag);
247 printf("debug: %d\n", args_info.debug_flag);
248 printf("qos: %#08x\n", args_info.qos_arg);
249 printf("apn: %s\n", args_info.apn_arg);
250 printf("net: %s\n", args_info.net_arg);
251 printf("mask: %s\n", args_info.mask_arg);
252 printf("pidfile: %s\n", args_info.pidfile_arg);
253 printf("statedir: %s\n", args_info.statedir_arg);
254 printf("timelimit: %d\n", args_info.timelimit_arg);
255 }
256
257 /* Try out our new parser */
258
259 if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0) != 0)
260 exit(1);
261 if (args_info.debug_flag) {
262 printf("cmdline_parser_configfile\n");
263 printf("listen: %s\n", args_info.listen_arg);
264 printf("conf: %s\n", args_info.conf_arg);
265 printf("fg: %d\n", args_info.fg_flag);
266 printf("debug: %d\n", args_info.debug_flag);
267 printf("qos: %#08x\n", args_info.qos_arg);
268 printf("apn: %s\n", args_info.apn_arg);
269 printf("net: %s\n", args_info.net_arg);
270 printf("mask: %s\n", args_info.mask_arg);
271 printf("pidfile: %s\n", args_info.pidfile_arg);
272 printf("statedir: %s\n", args_info.statedir_arg);
273 printf("timelimit: %d\n", args_info.timelimit_arg);
274 }
275
276 /* Handle each option */
277
278 /* foreground */
279 /* If flag not given run as a daemon */
280 if (!args_info.fg_flag)
281 {
282 closelog();
283 /* Close the standard file descriptors. */
284 /* Is this really needed ? */
285 freopen("/dev/null", "w", stdout);
286 freopen("/dev/null", "w", stderr);
287 freopen("/dev/null", "r", stdin);
288 daemon(0, 0);
289 /* Open log again. This time with new pid */
290 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
291 }
292
293 /* debug */
294 debug = args_info.debug_flag;
295
296 /* pidfile */
297 /* This has to be done after we have our final pid */
298 if (args_info.pidfile_arg) {
299 log_pid(args_info.pidfile_arg);
300 }
301
302 /* listen */
303 /* If no listen option is specified listen to any local port */
304 /* Do hostname lookup to translate hostname to IP address */
305 if (args_info.listen_arg) {
306 if (!(host = gethostbyname(args_info.listen_arg))) {
307 fprintf(stderr, "%s: Invalid listening address: %s!\n",
308 PACKAGE, args_info.listen_arg);
309 syslog(LOG_ERR, "Invalid listening address: %s!",
310 args_info.listen_arg);
311 return 1;
312 }
313 else {
314 memcpy(&listen.s_addr, host->h_addr, host->h_length);
315 }
316 }
317 else {
318 listen.s_addr = htonl(INADDR_ANY);
319 }
320
321 /* net */
322 /* Store net as in_addr */
323 if (args_info.net_arg) {
324 if (!inet_aton(args_info.net_arg, &net)) {
325 fprintf(stderr, "%s: Invalid network address: %s!\n",
326 PACKAGE, args_info.net_arg);
327 syslog(LOG_ERR, "Invalid network address: %s!",
328 args_info.net_arg);
329 return 1;
330 }
331 }
332
333 /* mask */
334 /* Store mask as in_addr */
335 if (args_info.mask_arg) {
336 if (!inet_aton(args_info.mask_arg, &mask)) {
337 fprintf(stderr, "%s: Invalid network mask: %s!\n",
338 PACKAGE, args_info.mask_arg);
339 syslog(LOG_ERR, "Invalid network mask: %s!",
340 args_info.mask_arg);
341 return 1;
342 }
343 }
344
345 /* Timelimit */
346 timelimit = args_info.timelimit_arg;
347 starttime = time(NULL);
348
349 /* qos */
350 qos.l = 3;
351 qos.v = qosh;
352 qos.v[2] = (args_info.qos_arg) & 0xff;
353 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
354 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
355
356 /* apn */
357 if (strlen(args_info.apn_arg)>255) {
358 printf("invalid APN\n");
359 exit(1);
360 }
361 apn.l = strlen(args_info.apn_arg) + 1;
362 apn.v = apnh;
363 apn.v[0] = (char) strlen(args_info.apn_arg);
364 strncpy(&apn.v[1], args_info.apn_arg, 255);
365
366 if (debug) printf("gtpclient: Initialising GTP tunnel\n");
367
368 if ((gtpfd = gtp_new(&gsn, args_info.statedir_arg, &listen)) > maxfd)
369 maxfd = gtpfd;
370
371 if ((gtpfd = gtp_fd(gsn)) > maxfd)
372 maxfd = gtpfd;
373
374
375 gtp_set_cb_gpdu(gsn, encaps_tun);
376 gtp_set_cb_delete_context(gsn, delete_context);
377
378 gtp_set_cb_create_context(gsn, create_context);
379 create_tun();
380
381 /******************************************************************/
382 /* Main select loop */
383 /******************************************************************/
384
385 while (((starttime + timelimit) > time(NULL)) || (0 == timelimit)) {
386
387 FD_ZERO(&fds);
388 if (tun_fd != -1) FD_SET(tun_fd, &fds);
389 if (gtpfd != -1) FD_SET(gtpfd, &fds);
390
391 gtp_retranstimeout(gsn, &idleTime);
392 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
393 case -1: /* Error with select() *
394 if (errno != EINTR)
395 syslog(LOG_ERR, "CTRL: Error with select(), quitting");
396 *goto leave_clear_call;*/
397 syslog(LOG_ERR, "GGSN: select = -1");
398 break;
399 case 0:
400 gtp_retrans(gsn); /* Only retransmit if nothing else */
401 break;
402 default:
403 break;
404 }
405
406 if (tun_fd != -1 && FD_ISSET(tun_fd, &fds) &&
407 tun_decaps(tun, encaps_gtp, gsn) < 0) {
408 syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun_fd);
409 }
410
411 if (gtpfd != -1 && FD_ISSET(gtpfd, &fds) &&
412 gtp_decaps(gsn) < 0) {
413 syslog(LOG_ERR, "GTP read failed (gre)=(%d)", gtpfd);
414 }
415
416
417 }
418
419 gtp_free(gsn);
420
421 return 1;
422
423}
424