blob: 53c8c01c1756978abf97b3820fb9c43e0acebd6b [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
jjakoa7cd2492003-04-11 09:40:12 +00002 * OpenGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
jjako52c24142002-12-16 13:33:51 +00004 *
jjakoa7cd2492003-04-11 09:40:12 +00005 * 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.
jjako52c24142002-12-16 13:33:51 +00009 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/* ggsn.c
13 *
14 */
15
16#ifdef __linux__
17#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
18#endif
19
jjako0fe0df02004-09-17 11:30:40 +000020#include "../config.h"
21
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010022#include <osmocom/core/application.h>
23
jjako0fe0df02004-09-17 11:30:40 +000024#ifdef HAVE_STDINT_H
25#include <stdint.h>
26#endif
jjako52c24142002-12-16 13:33:51 +000027
jjako52c24142002-12-16 13:33:51 +000028#include <ctype.h>
29#include <netdb.h>
30#include <signal.h>
31#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <sys/wait.h>
39#include <sys/stat.h>
jjako0141d202004-01-09 15:19:20 +000040#include <fcntl.h>
jjako52c24142002-12-16 13:33:51 +000041#include <unistd.h>
42
Harald Weltebed35df2011-11-02 13:06:18 +010043#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000044#include <sys/ioctl.h>
45#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000046
47#include <errno.h>
48
jjako52c24142002-12-16 13:33:51 +000049#include <time.h>
50
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020051#include "../lib/tun.h"
52#include "../lib/ippool.h"
53#include "../lib/syserr.h"
jjako52c24142002-12-16 13:33:51 +000054#include "../gtp/pdp.h"
55#include "../gtp/gtp.h"
56#include "cmdline.h"
57
Harald Weltec3dcba02010-05-04 11:02:54 +020058int end = 0;
Harald Weltebed35df2011-11-02 13:06:18 +010059int maxfd = 0; /* For select() */
jjakoa7cd2492003-04-11 09:40:12 +000060
61struct in_addr listen_;
Harald Weltebed35df2011-11-02 13:06:18 +010062struct in_addr netaddr, destaddr, net, mask; /* Network interface */
63struct in_addr dns1, dns2; /* PCO DNS address */
64char *ipup, *ipdown; /* Filename of scripts */
65int debug; /* Print debug output */
jjakoa7cd2492003-04-11 09:40:12 +000066struct ul255_t pco;
67struct ul255_t qos;
68struct ul255_t apn;
69
Harald Weltebed35df2011-11-02 13:06:18 +010070struct gsn_t *gsn; /* GSN instance */
71struct tun_t *tun; /* TUN instance */
72struct ippool_t *ippool; /* Pool of IP addresses */
jjako52c24142002-12-16 13:33:51 +000073
Harald Weltec3dcba02010-05-04 11:02:54 +020074/* To exit gracefully. Used with GCC compilation flag -pg and gprof */
Harald Weltebed35df2011-11-02 13:06:18 +010075void signal_handler(int s)
76{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +010077 DEBUGP(DGGSN, "Received signal %d, exiting.\n", s);
Harald Weltebed35df2011-11-02 13:06:18 +010078 end = 1;
Harald Weltec3dcba02010-05-04 11:02:54 +020079}
jjako52c24142002-12-16 13:33:51 +000080
81/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +010082void log_pid(char *pidfile)
83{
84 FILE *file;
85 mode_t oldmask;
86
87 oldmask = umask(022);
88 file = fopen(pidfile, "w");
89 umask(oldmask);
90 if (!file) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010091 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +010092 "Failed to create process ID file: %s!", pidfile);
93 return;
94 }
95 fprintf(file, "%d\n", (int)getpid());
96 fclose(file);
jjako52c24142002-12-16 13:33:51 +000097}
98
jjakobd937b72004-12-30 16:22:42 +000099#if defined(__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100100int daemon(int nochdir, int noclose)
101{
102 int fd;
jjako0141d202004-01-09 15:19:20 +0000103
Harald Weltebed35df2011-11-02 13:06:18 +0100104 switch (fork()) {
105 case -1:
106 return (-1);
107 case 0:
108 break;
109 default:
110 _exit(0);
111 }
jjako0141d202004-01-09 15:19:20 +0000112
Harald Weltebed35df2011-11-02 13:06:18 +0100113 if (setsid() == -1)
114 return (-1);
jjako0141d202004-01-09 15:19:20 +0000115
Harald Weltebed35df2011-11-02 13:06:18 +0100116 if (!nochdir)
117 chdir("/");
118
119 if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
120 dup2(fd, STDIN_FILENO);
121 dup2(fd, STDOUT_FILENO);
122 dup2(fd, STDERR_FILENO);
123 if (fd > 2)
124 close(fd);
125 }
126 return (0);
jjako0141d202004-01-09 15:19:20 +0000127}
128#endif
129
Harald Weltebed35df2011-11-02 13:06:18 +0100130int delete_context(struct pdp_t *pdp)
131{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100132 DEBUGP(DGGSN, "Deleting PDP context\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100133 if (pdp->peer)
134 ippool_freeip(ippool, (struct ippoolm_t *)pdp->peer);
135 else
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100136 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Peer not defined!");
Harald Weltebed35df2011-11-02 13:06:18 +0100137 return 0;
jjako52c24142002-12-16 13:33:51 +0000138}
139
Harald Weltebed35df2011-11-02 13:06:18 +0100140int create_context_ind(struct pdp_t *pdp)
141{
142 struct in_addr addr;
143 struct ippoolm_t *member;
jjako52c24142002-12-16 13:33:51 +0000144
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100145 DEBUGP(DGGSN, "Received create PDP context request\n");
jjako52c24142002-12-16 13:33:51 +0000146
Harald Weltebed35df2011-11-02 13:06:18 +0100147 pdp->eua.l = 0; /* TODO: Indicates dynamic IP */
jjako52c24142002-12-16 13:33:51 +0000148
Harald Weltebed35df2011-11-02 13:06:18 +0100149 /* ulcpy(&pdp->qos_neg, &pdp->qos_req, sizeof(pdp->qos_req.v)); */
150 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
151 memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg));
jjako52c24142002-12-16 13:33:51 +0000152
Harald Weltebed35df2011-11-02 13:06:18 +0100153 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
154 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000155
Harald Weltebed35df2011-11-02 13:06:18 +0100156 if (pdp_euaton(&pdp->eua, &addr)) {
157 addr.s_addr = 0; /* Request dynamic */
158 }
jjakoa7cd2492003-04-11 09:40:12 +0000159
Harald Weltebed35df2011-11-02 13:06:18 +0100160 if (ippool_newip(ippool, &member, &addr, 0)) {
161 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
162 return 0; /* Allready in use, or no more available */
163 }
jjakoa7cd2492003-04-11 09:40:12 +0000164
Harald Weltebed35df2011-11-02 13:06:18 +0100165 pdp_ntoeua(&member->addr, &pdp->eua);
166 pdp->peer = member;
167 pdp->ipif = tun; /* TODO */
168 member->peer = pdp;
jjako52c24142002-12-16 13:33:51 +0000169
Harald Weltebed35df2011-11-02 13:06:18 +0100170 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
171 return 0; /* Success */
jjako52c24142002-12-16 13:33:51 +0000172}
173
jjakoa7cd2492003-04-11 09:40:12 +0000174/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +0100175int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
176{
177 struct ippoolm_t *ipm;
178 struct in_addr dst;
179 struct tun_packet_t *iph = (struct tun_packet_t *)pack;
jjakoc6762cf2004-04-28 14:52:58 +0000180
Harald Weltebed35df2011-11-02 13:06:18 +0100181 dst.s_addr = iph->dst;
jjakoc6762cf2004-04-28 14:52:58 +0000182
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100183 DEBUGP(DGGSN, "Received packet from tun!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100184
185 if (ippool_getip(ippool, &ipm, &dst)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100186 DEBUGP(DGGSN, "Received packet with no destination!!!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100187 return 0;
188 }
189
190 if (ipm->peer) /* Check if a peer protocol is defined */
191 gtp_data_req(gsn, (struct pdp_t *)ipm->peer, pack, len);
192 return 0;
jjako52c24142002-12-16 13:33:51 +0000193}
194
Harald Weltebed35df2011-11-02 13:06:18 +0100195int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
196{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100197 DEBUGP(DGGSN, "encaps_tun. Packet received: forwarding to tun\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100198 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000199}
200
jjako52c24142002-12-16 13:33:51 +0000201int main(int argc, char **argv)
202{
Harald Weltebed35df2011-11-02 13:06:18 +0100203 /* gengeopt declarations */
204 struct gengetopt_args_info args_info;
jjako52c24142002-12-16 13:33:51 +0000205
Harald Weltebed35df2011-11-02 13:06:18 +0100206 struct hostent *host;
jjako52c24142002-12-16 13:33:51 +0000207
Harald Weltebed35df2011-11-02 13:06:18 +0100208 /* Handle keyboard interrupt SIGINT */
209 struct sigaction s;
210 s.sa_handler = (void *)signal_handler;
211 if ((0 != sigemptyset(&s.sa_mask)) && debug)
212 printf("sigemptyset failed.\n");
213 s.sa_flags = SA_RESETHAND;
214 if ((sigaction(SIGINT, &s, NULL) != 0) && debug)
215 printf("Could not register SIGINT signal handler.\n");
jjako52c24142002-12-16 13:33:51 +0000216
Harald Weltebed35df2011-11-02 13:06:18 +0100217 fd_set fds; /* For select() */
218 struct timeval idleTime; /* How long to select() */
jjako52c24142002-12-16 13:33:51 +0000219
Harald Weltebed35df2011-11-02 13:06:18 +0100220 int timelimit; /* Number of seconds to be connected */
221 int starttime; /* Time program was started */
jjako52c24142002-12-16 13:33:51 +0000222
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100223 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +0000224
Harald Weltebed35df2011-11-02 13:06:18 +0100225 if (cmdline_parser(argc, argv, &args_info) != 0)
226 exit(1);
227 if (args_info.debug_flag) {
228 printf("listen: %s\n", args_info.listen_arg);
229 if (args_info.conf_arg)
230 printf("conf: %s\n", args_info.conf_arg);
231 printf("fg: %d\n", args_info.fg_flag);
232 printf("debug: %d\n", args_info.debug_flag);
233 printf("qos: %#08x\n", args_info.qos_arg);
234 if (args_info.apn_arg)
235 printf("apn: %s\n", args_info.apn_arg);
236 if (args_info.net_arg)
237 printf("net: %s\n", args_info.net_arg);
238 if (args_info.dynip_arg)
239 printf("dynip: %s\n", args_info.dynip_arg);
240 if (args_info.statip_arg)
241 printf("statip: %s\n", args_info.statip_arg);
242 if (args_info.ipup_arg)
243 printf("ipup: %s\n", args_info.ipup_arg);
244 if (args_info.ipdown_arg)
245 printf("ipdown: %s\n", args_info.ipdown_arg);
246 if (args_info.pidfile_arg)
247 printf("pidfile: %s\n", args_info.pidfile_arg);
248 if (args_info.statedir_arg)
249 printf("statedir: %s\n", args_info.statedir_arg);
250 printf("timelimit: %d\n", args_info.timelimit_arg);
251 }
jjako52c24142002-12-16 13:33:51 +0000252
Harald Weltebed35df2011-11-02 13:06:18 +0100253 /* Try out our new parser */
jjako52c24142002-12-16 13:33:51 +0000254
Harald Weltebed35df2011-11-02 13:06:18 +0100255 if (cmdline_parser_configfile(args_info.conf_arg, &args_info, 0, 0, 0)
256 != 0)
257 exit(1);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100258
259 /* Open a log file */
260 if (args_info.logfile_arg) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100261 struct log_target *tgt;
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100262 int lvl;
263
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100264 tgt = log_target_find(LOG_TGT_TYPE_FILE, args_info.logfile_arg);
265 if (!tgt) {
266 tgt = log_target_create_file(args_info.logfile_arg);
267 if (!tgt) {
268 LOGP(DGGSN, LOGL_ERROR,
269 "Failed to create logfile: %s\n",
270 args_info.logfile_arg);
271 exit(1);
272 }
273 log_add_target(tgt);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100274 }
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100275 log_set_all_filter(tgt, 1);
276 log_set_use_color(tgt, 0);
277
278 if (args_info.loglevel_arg) {
279 lvl = log_parse_level(args_info.loglevel_arg);
280 log_set_log_level(tgt, lvl);
281 LOGP(DGGSN, LOGL_NOTICE,
282 "Set file log level to %s\n",
283 log_level_str(lvl));
284 }
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100285 }
286
Harald Weltebed35df2011-11-02 13:06:18 +0100287 if (args_info.debug_flag) {
288 printf("cmdline_parser_configfile\n");
289 printf("listen: %s\n", args_info.listen_arg);
290 printf("conf: %s\n", args_info.conf_arg);
291 printf("fg: %d\n", args_info.fg_flag);
292 printf("debug: %d\n", args_info.debug_flag);
293 printf("qos: %#08x\n", args_info.qos_arg);
294 if (args_info.apn_arg)
295 printf("apn: %s\n", args_info.apn_arg);
296 if (args_info.net_arg)
297 printf("net: %s\n", args_info.net_arg);
298 if (args_info.dynip_arg)
299 printf("dynip: %s\n", args_info.dynip_arg);
300 if (args_info.statip_arg)
301 printf("statip: %s\n", args_info.statip_arg);
302 if (args_info.ipup_arg)
303 printf("ipup: %s\n", args_info.ipup_arg);
304 if (args_info.ipdown_arg)
305 printf("ipdown: %s\n", args_info.ipdown_arg);
306 if (args_info.pidfile_arg)
307 printf("pidfile: %s\n", args_info.pidfile_arg);
308 if (args_info.statedir_arg)
309 printf("statedir: %s\n", args_info.statedir_arg);
310 printf("timelimit: %d\n", args_info.timelimit_arg);
311 }
jjako52c24142002-12-16 13:33:51 +0000312
Harald Weltebed35df2011-11-02 13:06:18 +0100313 /* Handle each option */
jjako52c24142002-12-16 13:33:51 +0000314
Harald Weltebed35df2011-11-02 13:06:18 +0100315 /* debug */
316 debug = args_info.debug_flag;
jjako52c24142002-12-16 13:33:51 +0000317
Harald Weltebed35df2011-11-02 13:06:18 +0100318 /* listen */
319 /* Do hostname lookup to translate hostname to IP address */
320 /* Any port listening is not possible as a valid address is */
321 /* required for create_pdp_context_response messages */
322 if (args_info.listen_arg) {
323 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100324 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100325 "Invalid listening address: %s!",
326 args_info.listen_arg);
327 exit(1);
328 } else {
329 memcpy(&listen_.s_addr, host->h_addr, host->h_length);
330 }
331 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100332 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100333 "Listening address must be specified! "
334 "Please use command line option --listen or "
335 "edit %s configuration file\n", args_info.conf_arg);
336 exit(1);
337 }
jjako88c22162003-07-06 19:33:18 +0000338
Harald Weltebed35df2011-11-02 13:06:18 +0100339 /* net */
340 /* Store net as in_addr net and mask */
341 if (args_info.net_arg) {
342 if (ippool_aton(&net, &mask, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100343 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100344 "Invalid network address: %s!",
345 args_info.net_arg);
346 exit(1);
347 }
348 netaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
349 destaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
350 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100351 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100352 "Network address must be specified: %s!",
353 args_info.net_arg);
354 exit(1);
355 }
jjako52c24142002-12-16 13:33:51 +0000356
Harald Weltebed35df2011-11-02 13:06:18 +0100357 /* dynip */
358 if (!args_info.dynip_arg) {
359 if (ippool_new(&ippool, args_info.net_arg, NULL, 1, 0,
360 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
361 IPPOOL_NOBROADCAST)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100362 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100363 "Failed to allocate IP pool!");
364 exit(1);
365 }
366 } else {
367 if (ippool_new(&ippool, args_info.dynip_arg, NULL, 1, 0,
368 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
369 IPPOOL_NOBROADCAST)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100370 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100371 "Failed to allocate IP pool!");
372 exit(1);
373 }
374 }
jjako52c24142002-12-16 13:33:51 +0000375
Harald Weltebed35df2011-11-02 13:06:18 +0100376 /* DNS1 and DNS2 */
jjakoff9985c2004-01-16 11:05:22 +0000377#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +0100378 dns1.s_addr = 0;
379 if (args_info.pcodns1_arg) {
380 if (0 == inet_aton(args_info.pcodns1_arg, &dns1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100381 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100382 "Failed to convert pcodns1!");
383 exit(1);
384 }
385 }
386 dns2.s_addr = 0;
387 if (args_info.pcodns2_arg) {
388 if (0 == inet_aton(args_info.pcodns2_arg, &dns2)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100389 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100390 "Failed to convert pcodns2!");
391 exit(1);
392 }
393 }
jjako1d3db972004-01-16 09:56:56 +0000394#else
Harald Weltebed35df2011-11-02 13:06:18 +0100395 dns1.s_addr = 0;
396 if (args_info.pcodns1_arg) {
397 dns1.s_addr = inet_addr(args_info.pcodns1_arg);
398 if (dns1.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100399 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100400 "Failed to convert pcodns1!");
401 exit(1);
402 }
403 }
404 dns2.s_addr = 0;
405 if (args_info.pcodns2_arg) {
406 dns2.s_addr = inet_addr(args_info.pcodns2_arg);
407 if (dns2.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100408 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100409 "Failed to convert pcodns2!");
410 exit(1);
411 }
412 }
jjako1d3db972004-01-16 09:56:56 +0000413#endif
414
Harald Weltebed35df2011-11-02 13:06:18 +0100415 pco.l = 20;
416 pco.v[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
417 pco.v[1] = 0x80; /* IPCP */
418 pco.v[2] = 0x21;
419 pco.v[3] = 0x10; /* Length of contents */
420 pco.v[4] = 0x02; /* ACK */
421 pco.v[5] = 0x00; /* ID: Need to match request */
422 pco.v[6] = 0x00; /* Length */
423 pco.v[7] = 0x10;
424 pco.v[8] = 0x81; /* DNS 1 */
425 pco.v[9] = 0x06;
426 memcpy(&pco.v[10], &dns1, sizeof(dns1));
427 pco.v[14] = 0x83;
428 pco.v[15] = 0x06; /* DNS 2 */
429 memcpy(&pco.v[16], &dns2, sizeof(dns2));
jjakoa7cd2492003-04-11 09:40:12 +0000430
Harald Weltebed35df2011-11-02 13:06:18 +0100431 /* ipup */
432 ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000433
Harald Weltebed35df2011-11-02 13:06:18 +0100434 /* ipdown */
435 ipdown = args_info.ipdown_arg;
jjako4b26b512003-01-28 16:13:57 +0000436
Harald Weltebed35df2011-11-02 13:06:18 +0100437 /* Timelimit */
438 timelimit = args_info.timelimit_arg;
439 starttime = time(NULL);
jjako4b26b512003-01-28 16:13:57 +0000440
Harald Weltebed35df2011-11-02 13:06:18 +0100441 /* qos */
442 qos.l = 3;
443 qos.v[2] = (args_info.qos_arg) & 0xff;
444 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
445 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
jjakoa7cd2492003-04-11 09:40:12 +0000446
Harald Weltebed35df2011-11-02 13:06:18 +0100447 /* apn */
448 if (strlen(args_info.apn_arg) > (sizeof(apn.v) - 1)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100449 LOGP(DGGSN, LOGL_ERROR, "Invalid APN\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100450 return -1;
451 }
452 apn.l = strlen(args_info.apn_arg) + 1;
453 apn.v[0] = (char)strlen(args_info.apn_arg);
454 strncpy((char *)&apn.v[1], args_info.apn_arg, sizeof(apn.v) - 1);
jjakoe0149782003-07-06 17:07:04 +0000455
Harald Weltebed35df2011-11-02 13:06:18 +0100456 /* foreground */
457 /* If flag not given run as a daemon */
458 if (!args_info.fg_flag) {
459 FILE *f;
460 int rc;
Harald Weltebed35df2011-11-02 13:06:18 +0100461 /* Close the standard file descriptors. */
462 /* Is this really needed ? */
463 f = freopen("/dev/null", "w", stdout);
464 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100465 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100466 "Could not redirect stdout to /dev/null");
467 }
468 f = freopen("/dev/null", "w", stderr);
469 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100470 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100471 "Could not redirect stderr to /dev/null");
472 }
473 f = freopen("/dev/null", "r", stdin);
474 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100475 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100476 "Could not redirect stdin to /dev/null");
477 }
478 rc = daemon(0, 0);
479 if (rc != 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100480 SYS_ERR(DGGSN, LOGL_ERROR, rc,
Harald Weltebed35df2011-11-02 13:06:18 +0100481 "Could not daemonize");
482 exit(1);
483 }
Harald Weltebed35df2011-11-02 13:06:18 +0100484 }
jjakoe0149782003-07-06 17:07:04 +0000485
Harald Weltebed35df2011-11-02 13:06:18 +0100486 /* pidfile */
487 /* This has to be done after we have our final pid */
488 if (args_info.pidfile_arg) {
489 log_pid(args_info.pidfile_arg);
490 }
jjakoe0149782003-07-06 17:07:04 +0000491
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100492 DEBUGP(DGGSN, "gtpclient: Initialising GTP tunnel\n");
jjako52c24142002-12-16 13:33:51 +0000493
Harald Weltebed35df2011-11-02 13:06:18 +0100494 if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100495 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +0100496 exit(1);
497 }
498 if (gsn->fd0 > maxfd)
499 maxfd = gsn->fd0;
500 if (gsn->fd1c > maxfd)
501 maxfd = gsn->fd1c;
502 if (gsn->fd1u > maxfd)
503 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +0000504
Harald Weltebed35df2011-11-02 13:06:18 +0100505 gtp_set_cb_data_ind(gsn, encaps_tun);
506 gtp_set_cb_delete_context(gsn, delete_context);
507 gtp_set_cb_create_context_ind(gsn, create_context_ind);
jjakoa7cd2492003-04-11 09:40:12 +0000508
Harald Weltebed35df2011-11-02 13:06:18 +0100509 /* Create a tunnel interface */
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100510 DEBUGP(DGGSN, "Creating tun interface\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100511 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100512 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create tun");
Harald Weltebed35df2011-11-02 13:06:18 +0100513 exit(1);
514 }
jjakoa7cd2492003-04-11 09:40:12 +0000515
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100516 DEBUGP(DGGSN, "Setting tun IP address\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100517 if (tun_setaddr(tun, &netaddr, &destaddr, &mask)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100518 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to set tun IP address");
Harald Weltebed35df2011-11-02 13:06:18 +0100519 exit(1);
520 }
jjakoa7cd2492003-04-11 09:40:12 +0000521
Harald Weltebed35df2011-11-02 13:06:18 +0100522 tun_set_cb_ind(tun, cb_tun_ind);
523 if (tun->fd > maxfd)
524 maxfd = tun->fd;
jjakoc6762cf2004-04-28 14:52:58 +0000525
Harald Weltebed35df2011-11-02 13:06:18 +0100526 if (ipup)
527 tun_runscript(tun, ipup);
jjako52c24142002-12-16 13:33:51 +0000528
529 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +0100530 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +0000531 /******************************************************************/
532
Harald Weltebed35df2011-11-02 13:06:18 +0100533 while ((((starttime + timelimit) > time(NULL)) || (0 == timelimit))
534 && (!end)) {
Harald Weltec3dcba02010-05-04 11:02:54 +0200535
Harald Weltebed35df2011-11-02 13:06:18 +0100536 FD_ZERO(&fds);
537 if (tun)
538 FD_SET(tun->fd, &fds);
539 FD_SET(gsn->fd0, &fds);
540 FD_SET(gsn->fd1c, &fds);
541 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +0000542
Harald Weltebed35df2011-11-02 13:06:18 +0100543 gtp_retranstimeout(gsn, &idleTime);
544 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
545 case -1: /* errno == EINTR : unblocked signal */
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100546 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100547 "select() returned -1");
548 /* On error, select returns without modifying fds */
549 FD_ZERO(&fds);
550 break;
551 case 0:
552 /* printf("Select returned 0\n"); */
553 gtp_retrans(gsn); /* Only retransmit if nothing else */
554 break;
555 default:
556 break;
557 }
jjako52c24142002-12-16 13:33:51 +0000558
Harald Weltebed35df2011-11-02 13:06:18 +0100559 if (tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
560 tun_decaps(tun) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100561 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100562 "TUN read failed (fd)=(%d)", tun->fd);
563 }
564
565 if (FD_ISSET(gsn->fd0, &fds))
566 gtp_decaps0(gsn);
567
568 if (FD_ISSET(gsn->fd1c, &fds))
569 gtp_decaps1c(gsn);
570
571 if (FD_ISSET(gsn->fd1u, &fds))
572 gtp_decaps1u(gsn);
573
574 }
575
576 cmdline_parser_free(&args_info);
577 ippool_free(ippool);
578 gtp_free(gsn);
579 tun_free(tun);
580
581 return 1;
582
jjako52c24142002-12-16 13:33:51 +0000583}