blob: 8e7d1e312d8d34ca4ea7b05828e6b2537434129c [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>
Harald Welte63ebccd2017-08-02 21:10:09 +020037#include <netinet/ip.h>
Harald Weltea0d281d2017-08-02 21:48:16 +020038#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000039#include <arpa/inet.h>
40#include <sys/wait.h>
41#include <sys/stat.h>
jjako0141d202004-01-09 15:19:20 +000042#include <fcntl.h>
jjako52c24142002-12-16 13:33:51 +000043#include <unistd.h>
Max727417d2016-08-02 17:10:38 +020044#include <inttypes.h>
Harald Weltebed35df2011-11-02 13:06:18 +010045#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000046#include <sys/ioctl.h>
47#include <net/if.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020048#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000049
50#include <errno.h>
51
jjako52c24142002-12-16 13:33:51 +000052#include <time.h>
53
Max727417d2016-08-02 17:10:38 +020054#include <osmocom/core/select.h>
55#include <osmocom/ctrl/control_if.h>
56#include <osmocom/ctrl/control_cmd.h>
57#include <osmocom/ctrl/ports.h>
58
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020059#include "../lib/tun.h"
60#include "../lib/ippool.h"
61#include "../lib/syserr.h"
Harald Welted12eab92017-08-02 19:49:47 +020062#include "../lib/in46_addr.h"
jjako52c24142002-12-16 13:33:51 +000063#include "../gtp/pdp.h"
64#include "../gtp/gtp.h"
65#include "cmdline.h"
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +010066#include "gtp-kernel.h"
jjako52c24142002-12-16 13:33:51 +000067
Harald Weltec3dcba02010-05-04 11:02:54 +020068int end = 0;
Harald Weltebed35df2011-11-02 13:06:18 +010069int maxfd = 0; /* For select() */
jjakoa7cd2492003-04-11 09:40:12 +000070
71struct in_addr listen_;
Harald Welted12eab92017-08-02 19:49:47 +020072struct in_addr netaddr, destaddr, net; /* Network interface */
73size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +010074struct in_addr dns1, dns2; /* PCO DNS address */
75char *ipup, *ipdown; /* Filename of scripts */
76int debug; /* Print debug output */
jjakoa7cd2492003-04-11 09:40:12 +000077struct ul255_t pco;
78struct ul255_t qos;
79struct ul255_t apn;
80
Harald Weltebed35df2011-11-02 13:06:18 +010081struct gsn_t *gsn; /* GSN instance */
82struct tun_t *tun; /* TUN instance */
83struct ippool_t *ippool; /* Pool of IP addresses */
jjako52c24142002-12-16 13:33:51 +000084
Harald Weltec3dcba02010-05-04 11:02:54 +020085/* To exit gracefully. Used with GCC compilation flag -pg and gprof */
Harald Weltebed35df2011-11-02 13:06:18 +010086void signal_handler(int s)
87{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +010088 DEBUGP(DGGSN, "Received signal %d, exiting.\n", s);
Harald Weltebed35df2011-11-02 13:06:18 +010089 end = 1;
Harald Weltec3dcba02010-05-04 11:02:54 +020090}
jjako52c24142002-12-16 13:33:51 +000091
92/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +010093void log_pid(char *pidfile)
94{
95 FILE *file;
96 mode_t oldmask;
97
98 oldmask = umask(022);
99 file = fopen(pidfile, "w");
100 umask(oldmask);
101 if (!file) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100102 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100103 "Failed to create process ID file: %s!", pidfile);
104 return;
105 }
106 fprintf(file, "%d\n", (int)getpid());
107 fclose(file);
jjako52c24142002-12-16 13:33:51 +0000108}
109
jjakobd937b72004-12-30 16:22:42 +0000110#if defined(__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100111int daemon(int nochdir, int noclose)
112{
113 int fd;
jjako0141d202004-01-09 15:19:20 +0000114
Harald Weltebed35df2011-11-02 13:06:18 +0100115 switch (fork()) {
116 case -1:
117 return (-1);
118 case 0:
119 break;
120 default:
121 _exit(0);
122 }
jjako0141d202004-01-09 15:19:20 +0000123
Harald Weltebed35df2011-11-02 13:06:18 +0100124 if (setsid() == -1)
125 return (-1);
jjako0141d202004-01-09 15:19:20 +0000126
Harald Weltebed35df2011-11-02 13:06:18 +0100127 if (!nochdir)
128 chdir("/");
129
130 if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
131 dup2(fd, STDIN_FILENO);
132 dup2(fd, STDOUT_FILENO);
133 dup2(fd, STDERR_FILENO);
134 if (fd > 2)
135 close(fd);
136 }
137 return (0);
jjako0141d202004-01-09 15:19:20 +0000138}
139#endif
140
Max3142d8d2017-05-04 17:45:10 +0200141static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const struct ippoolm_t *member, const char *var)
142{
Harald Welted12eab92017-08-02 19:49:47 +0200143 char addrbuf[256];
Max3142d8d2017-05-04 17:45:10 +0200144 char val[NAMESIZE];
145
Harald Welted12eab92017-08-02 19:49:47 +0200146 const char *addrstr = in46a_ntop(&member->addr, addrbuf, sizeof(addrbuf));
147
148 snprintf(val, sizeof(val), "%" PRIu64 ",%s", pdp->imsi, addrstr);
Max3142d8d2017-05-04 17:45:10 +0200149
150 if (ctrl_cmd_send_trap(gsn->ctrl, var, val) < 0) {
151 LOGP(DGGSN, LOGL_ERROR, "Failed to create and send TRAP for IMSI %" PRIu64 " [%s].\n", pdp->imsi, var);
152 return false;
153 }
154 return true;
155}
156
Harald Weltebed35df2011-11-02 13:06:18 +0100157int delete_context(struct pdp_t *pdp)
158{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100159 DEBUGP(DGGSN, "Deleting PDP context\n");
Max727417d2016-08-02 17:10:38 +0200160 struct ippoolm_t *member = pdp->peer;
Maxdbd70242016-10-14 13:38:05 +0200161
162 if (pdp->peer) {
Max3142d8d2017-05-04 17:45:10 +0200163 send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
Harald Weltebed35df2011-11-02 13:06:18 +0100164 ippool_freeip(ippool, (struct ippoolm_t *)pdp->peer);
Maxdbd70242016-10-14 13:38:05 +0200165 } else
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100166 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Peer not defined!");
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100167
168 if (gtp_kernel_tunnel_del(pdp)) {
169 SYS_ERR(DGGSN, LOGL_ERROR, 0,
170 "Cannot delete tunnel from kernel: %s\n",
171 strerror(errno));
172 }
173
Harald Weltebed35df2011-11-02 13:06:18 +0100174 return 0;
jjako52c24142002-12-16 13:33:51 +0000175}
176
Harald Weltebed35df2011-11-02 13:06:18 +0100177int create_context_ind(struct pdp_t *pdp)
178{
Harald Welted12eab92017-08-02 19:49:47 +0200179 struct in46_addr addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100180 struct ippoolm_t *member;
jjako52c24142002-12-16 13:33:51 +0000181
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100182 DEBUGP(DGGSN, "Received create PDP context request\n");
jjako52c24142002-12-16 13:33:51 +0000183
Harald Welted9d88622017-08-04 00:22:35 +0200184 /* FIXME: we manually force all context requests to dynamic here! */
185 if (pdp->eua.l > 2)
186 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +0000187
Harald Weltebed35df2011-11-02 13:06:18 +0100188 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
189 memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg));
jjako52c24142002-12-16 13:33:51 +0000190
Harald Weltebed35df2011-11-02 13:06:18 +0100191 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
192 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000193
Harald Weltea0d281d2017-08-02 21:48:16 +0200194 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Welted12eab92017-08-02 19:49:47 +0200195 addr.v4.s_addr = 0; /* Request dynamic */
Harald Weltebed35df2011-11-02 13:06:18 +0100196 }
jjakoa7cd2492003-04-11 09:40:12 +0000197
Harald Weltebed35df2011-11-02 13:06:18 +0100198 if (ippool_newip(ippool, &member, &addr, 0)) {
199 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
200 return 0; /* Allready in use, or no more available */
201 }
jjakoa7cd2492003-04-11 09:40:12 +0000202
Harald Weltea0d281d2017-08-02 21:48:16 +0200203 in46a_to_eua(&member->addr, &pdp->eua);
Harald Weltebed35df2011-11-02 13:06:18 +0100204 pdp->peer = member;
205 pdp->ipif = tun; /* TODO */
206 member->peer = pdp;
jjako52c24142002-12-16 13:33:51 +0000207
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100208 if (gtp_kernel_tunnel_add(pdp) < 0) {
Andreas Schultzc5fbf9b2015-11-17 12:22:43 +0100209 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100210 "Cannot add tunnel to kernel: %s\n", strerror(errno));
211 }
Max3142d8d2017-05-04 17:45:10 +0200212
213 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200214 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
215 return 0;
216 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100217
Harald Weltebed35df2011-11-02 13:06:18 +0100218 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
219 return 0; /* Success */
jjako52c24142002-12-16 13:33:51 +0000220}
221
jjakoa7cd2492003-04-11 09:40:12 +0000222/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +0100223int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
224{
225 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200226 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200227 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200228 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoc6762cf2004-04-28 14:52:58 +0000229
Harald Welte63ebccd2017-08-02 21:10:09 +0200230 if (iph->version == 4) {
Harald Welted12eab92017-08-02 19:49:47 +0200231 if (len < sizeof(*iph) || len < 4*iph->ihl)
232 return -1;
233 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200234 dst.v4.s_addr = iph->daddr;
Harald Weltea0d281d2017-08-02 21:48:16 +0200235 } else if (iph->version == 6) {
236 dst.len = 16;
237 dst.v6 = ip6h->ip6_dst;
Harald Welted12eab92017-08-02 19:49:47 +0200238 } else {
Harald Weltea0d281d2017-08-02 21:48:16 +0200239 LOGP(DGGSN, LOGL_NOTICE, "non-IPv packet received from tun\n");
Harald Welted12eab92017-08-02 19:49:47 +0200240 return -1;
241 }
jjakoc6762cf2004-04-28 14:52:58 +0000242
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100243 DEBUGP(DGGSN, "Received packet from tun!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100244
245 if (ippool_getip(ippool, &ipm, &dst)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100246 DEBUGP(DGGSN, "Received packet with no destination!!!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100247 return 0;
248 }
249
250 if (ipm->peer) /* Check if a peer protocol is defined */
251 gtp_data_req(gsn, (struct pdp_t *)ipm->peer, pack, len);
252 return 0;
jjako52c24142002-12-16 13:33:51 +0000253}
254
Harald Weltebed35df2011-11-02 13:06:18 +0100255int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
256{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100257 DEBUGP(DGGSN, "encaps_tun. Packet received: forwarding to tun\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100258 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000259}
260
jjako52c24142002-12-16 13:33:51 +0000261int main(int argc, char **argv)
262{
Harald Weltebed35df2011-11-02 13:06:18 +0100263 /* gengeopt declarations */
264 struct gengetopt_args_info args_info;
jjako52c24142002-12-16 13:33:51 +0000265
Harald Weltebed35df2011-11-02 13:06:18 +0100266 struct hostent *host;
jjako52c24142002-12-16 13:33:51 +0000267
Harald Weltebed35df2011-11-02 13:06:18 +0100268 /* Handle keyboard interrupt SIGINT */
269 struct sigaction s;
270 s.sa_handler = (void *)signal_handler;
271 if ((0 != sigemptyset(&s.sa_mask)) && debug)
272 printf("sigemptyset failed.\n");
273 s.sa_flags = SA_RESETHAND;
274 if ((sigaction(SIGINT, &s, NULL) != 0) && debug)
275 printf("Could not register SIGINT signal handler.\n");
jjako52c24142002-12-16 13:33:51 +0000276
Harald Weltebed35df2011-11-02 13:06:18 +0100277 fd_set fds; /* For select() */
278 struct timeval idleTime; /* How long to select() */
jjako52c24142002-12-16 13:33:51 +0000279
Harald Weltebed35df2011-11-02 13:06:18 +0100280 int timelimit; /* Number of seconds to be connected */
281 int starttime; /* Time program was started */
jjako52c24142002-12-16 13:33:51 +0000282
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100283 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +0000284
Harald Weltebed35df2011-11-02 13:06:18 +0100285 if (cmdline_parser(argc, argv, &args_info) != 0)
286 exit(1);
287 if (args_info.debug_flag) {
288 printf("listen: %s\n", args_info.listen_arg);
289 if (args_info.conf_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);
Pablo Neira Ayusod9d7be32016-05-10 18:43:12 +0200310 if (args_info.gtp_linux_flag)
311 printf("gtp_linux: %d\n", args_info.gtp_linux_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100312 printf("timelimit: %d\n", args_info.timelimit_arg);
313 }
jjako52c24142002-12-16 13:33:51 +0000314
Harald Weltebed35df2011-11-02 13:06:18 +0100315 /* Try out our new parser */
jjako52c24142002-12-16 13:33:51 +0000316
Harald Weltebed35df2011-11-02 13:06:18 +0100317 if (cmdline_parser_configfile(args_info.conf_arg, &args_info, 0, 0, 0)
318 != 0)
319 exit(1);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100320
321 /* Open a log file */
322 if (args_info.logfile_arg) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100323 struct log_target *tgt;
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100324 int lvl;
325
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100326 tgt = log_target_find(LOG_TGT_TYPE_FILE, args_info.logfile_arg);
327 if (!tgt) {
328 tgt = log_target_create_file(args_info.logfile_arg);
329 if (!tgt) {
330 LOGP(DGGSN, LOGL_ERROR,
331 "Failed to create logfile: %s\n",
332 args_info.logfile_arg);
333 exit(1);
334 }
335 log_add_target(tgt);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100336 }
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100337 log_set_all_filter(tgt, 1);
338 log_set_use_color(tgt, 0);
339
340 if (args_info.loglevel_arg) {
341 lvl = log_parse_level(args_info.loglevel_arg);
342 log_set_log_level(tgt, lvl);
343 LOGP(DGGSN, LOGL_NOTICE,
344 "Set file log level to %s\n",
345 log_level_str(lvl));
346 }
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100347 }
348
Harald Weltebed35df2011-11-02 13:06:18 +0100349 if (args_info.debug_flag) {
350 printf("cmdline_parser_configfile\n");
351 printf("listen: %s\n", args_info.listen_arg);
352 printf("conf: %s\n", args_info.conf_arg);
353 printf("fg: %d\n", args_info.fg_flag);
354 printf("debug: %d\n", args_info.debug_flag);
355 printf("qos: %#08x\n", args_info.qos_arg);
356 if (args_info.apn_arg)
357 printf("apn: %s\n", args_info.apn_arg);
358 if (args_info.net_arg)
359 printf("net: %s\n", args_info.net_arg);
360 if (args_info.dynip_arg)
361 printf("dynip: %s\n", args_info.dynip_arg);
362 if (args_info.statip_arg)
363 printf("statip: %s\n", args_info.statip_arg);
364 if (args_info.ipup_arg)
365 printf("ipup: %s\n", args_info.ipup_arg);
366 if (args_info.ipdown_arg)
367 printf("ipdown: %s\n", args_info.ipdown_arg);
368 if (args_info.pidfile_arg)
369 printf("pidfile: %s\n", args_info.pidfile_arg);
370 if (args_info.statedir_arg)
371 printf("statedir: %s\n", args_info.statedir_arg);
Pablo Neira Ayusod9d7be32016-05-10 18:43:12 +0200372 if (args_info.gtp_linux_flag)
373 printf("gtp-linux: %d\n", args_info.gtp_linux_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100374 printf("timelimit: %d\n", args_info.timelimit_arg);
375 }
jjako52c24142002-12-16 13:33:51 +0000376
Harald Weltebed35df2011-11-02 13:06:18 +0100377 /* Handle each option */
jjako52c24142002-12-16 13:33:51 +0000378
Harald Weltebed35df2011-11-02 13:06:18 +0100379 /* debug */
380 debug = args_info.debug_flag;
jjako52c24142002-12-16 13:33:51 +0000381
Harald Weltebed35df2011-11-02 13:06:18 +0100382 /* listen */
383 /* Do hostname lookup to translate hostname to IP address */
384 /* Any port listening is not possible as a valid address is */
385 /* required for create_pdp_context_response messages */
386 if (args_info.listen_arg) {
387 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100388 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100389 "Invalid listening address: %s!",
390 args_info.listen_arg);
391 exit(1);
392 } else {
393 memcpy(&listen_.s_addr, host->h_addr, host->h_length);
394 }
395 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100396 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100397 "Listening address must be specified! "
398 "Please use command line option --listen or "
399 "edit %s configuration file\n", args_info.conf_arg);
400 exit(1);
401 }
jjako88c22162003-07-06 19:33:18 +0000402
Harald Weltebed35df2011-11-02 13:06:18 +0100403 /* net */
404 /* Store net as in_addr net and mask */
405 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200406 struct in46_addr in46;
407 if (ippool_aton(&in46, &prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100408 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100409 "Invalid network address: %s!",
410 args_info.net_arg);
411 exit(1);
412 }
Harald Welted12eab92017-08-02 19:49:47 +0200413 net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100414 netaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
415 destaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
416 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100417 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100418 "Network address must be specified: %s!",
419 args_info.net_arg);
420 exit(1);
421 }
jjako52c24142002-12-16 13:33:51 +0000422
Harald Weltebed35df2011-11-02 13:06:18 +0100423 /* dynip */
424 if (!args_info.dynip_arg) {
425 if (ippool_new(&ippool, args_info.net_arg, NULL, 1, 0,
426 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
427 IPPOOL_NOBROADCAST)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100428 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100429 "Failed to allocate IP pool!");
430 exit(1);
431 }
432 } else {
433 if (ippool_new(&ippool, args_info.dynip_arg, NULL, 1, 0,
434 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
435 IPPOOL_NOBROADCAST)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100436 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100437 "Failed to allocate IP pool!");
438 exit(1);
439 }
440 }
jjako52c24142002-12-16 13:33:51 +0000441
Harald Weltebed35df2011-11-02 13:06:18 +0100442 /* DNS1 and DNS2 */
jjakoff9985c2004-01-16 11:05:22 +0000443#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +0100444 dns1.s_addr = 0;
445 if (args_info.pcodns1_arg) {
446 if (0 == inet_aton(args_info.pcodns1_arg, &dns1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100447 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100448 "Failed to convert pcodns1!");
449 exit(1);
450 }
451 }
452 dns2.s_addr = 0;
453 if (args_info.pcodns2_arg) {
454 if (0 == inet_aton(args_info.pcodns2_arg, &dns2)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100455 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100456 "Failed to convert pcodns2!");
457 exit(1);
458 }
459 }
jjako1d3db972004-01-16 09:56:56 +0000460#else
Harald Weltebed35df2011-11-02 13:06:18 +0100461 dns1.s_addr = 0;
462 if (args_info.pcodns1_arg) {
463 dns1.s_addr = inet_addr(args_info.pcodns1_arg);
464 if (dns1.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100465 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100466 "Failed to convert pcodns1!");
467 exit(1);
468 }
469 }
470 dns2.s_addr = 0;
471 if (args_info.pcodns2_arg) {
472 dns2.s_addr = inet_addr(args_info.pcodns2_arg);
473 if (dns2.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100474 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100475 "Failed to convert pcodns2!");
476 exit(1);
477 }
478 }
jjako1d3db972004-01-16 09:56:56 +0000479#endif
480
Harald Weltebed35df2011-11-02 13:06:18 +0100481 pco.l = 20;
482 pco.v[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
483 pco.v[1] = 0x80; /* IPCP */
484 pco.v[2] = 0x21;
485 pco.v[3] = 0x10; /* Length of contents */
486 pco.v[4] = 0x02; /* ACK */
487 pco.v[5] = 0x00; /* ID: Need to match request */
488 pco.v[6] = 0x00; /* Length */
489 pco.v[7] = 0x10;
490 pco.v[8] = 0x81; /* DNS 1 */
491 pco.v[9] = 0x06;
492 memcpy(&pco.v[10], &dns1, sizeof(dns1));
493 pco.v[14] = 0x83;
494 pco.v[15] = 0x06; /* DNS 2 */
495 memcpy(&pco.v[16], &dns2, sizeof(dns2));
jjakoa7cd2492003-04-11 09:40:12 +0000496
Harald Weltebed35df2011-11-02 13:06:18 +0100497 /* ipup */
498 ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000499
Harald Weltebed35df2011-11-02 13:06:18 +0100500 /* ipdown */
501 ipdown = args_info.ipdown_arg;
jjako4b26b512003-01-28 16:13:57 +0000502
Harald Weltebed35df2011-11-02 13:06:18 +0100503 /* Timelimit */
504 timelimit = args_info.timelimit_arg;
505 starttime = time(NULL);
jjako4b26b512003-01-28 16:13:57 +0000506
Harald Weltebed35df2011-11-02 13:06:18 +0100507 /* qos */
508 qos.l = 3;
509 qos.v[2] = (args_info.qos_arg) & 0xff;
510 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
511 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
jjakoa7cd2492003-04-11 09:40:12 +0000512
Harald Weltebed35df2011-11-02 13:06:18 +0100513 /* apn */
514 if (strlen(args_info.apn_arg) > (sizeof(apn.v) - 1)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100515 LOGP(DGGSN, LOGL_ERROR, "Invalid APN\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100516 return -1;
517 }
518 apn.l = strlen(args_info.apn_arg) + 1;
519 apn.v[0] = (char)strlen(args_info.apn_arg);
520 strncpy((char *)&apn.v[1], args_info.apn_arg, sizeof(apn.v) - 1);
jjakoe0149782003-07-06 17:07:04 +0000521
Harald Weltebed35df2011-11-02 13:06:18 +0100522 /* foreground */
523 /* If flag not given run as a daemon */
524 if (!args_info.fg_flag) {
525 FILE *f;
526 int rc;
Harald Weltebed35df2011-11-02 13:06:18 +0100527 /* Close the standard file descriptors. */
528 /* Is this really needed ? */
529 f = freopen("/dev/null", "w", stdout);
530 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100531 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100532 "Could not redirect stdout to /dev/null");
533 }
534 f = freopen("/dev/null", "w", stderr);
535 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100536 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100537 "Could not redirect stderr to /dev/null");
538 }
539 f = freopen("/dev/null", "r", stdin);
540 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100541 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100542 "Could not redirect stdin to /dev/null");
543 }
544 rc = daemon(0, 0);
545 if (rc != 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100546 SYS_ERR(DGGSN, LOGL_ERROR, rc,
Harald Weltebed35df2011-11-02 13:06:18 +0100547 "Could not daemonize");
548 exit(1);
549 }
Harald Weltebed35df2011-11-02 13:06:18 +0100550 }
jjakoe0149782003-07-06 17:07:04 +0000551
Harald Weltebed35df2011-11-02 13:06:18 +0100552 /* pidfile */
553 /* This has to be done after we have our final pid */
554 if (args_info.pidfile_arg) {
555 log_pid(args_info.pidfile_arg);
556 }
jjakoe0149782003-07-06 17:07:04 +0000557
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100558 DEBUGP(DGGSN, "gtpclient: Initialising GTP tunnel\n");
jjako52c24142002-12-16 13:33:51 +0000559
Harald Weltebed35df2011-11-02 13:06:18 +0100560 if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100561 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +0100562 exit(1);
563 }
564 if (gsn->fd0 > maxfd)
565 maxfd = gsn->fd0;
566 if (gsn->fd1c > maxfd)
567 maxfd = gsn->fd1c;
568 if (gsn->fd1u > maxfd)
569 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +0000570
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100571 /* use GTP kernel module for data packet encapsulation */
Harald Welted12eab92017-08-02 19:49:47 +0200572 if (gtp_kernel_init(gsn, &net, prefixlen, &args_info) < 0)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100573 goto err;
574
Harald Weltebed35df2011-11-02 13:06:18 +0100575 gtp_set_cb_data_ind(gsn, encaps_tun);
576 gtp_set_cb_delete_context(gsn, delete_context);
577 gtp_set_cb_create_context_ind(gsn, create_context_ind);
jjakoa7cd2492003-04-11 09:40:12 +0000578
Max727417d2016-08-02 17:10:38 +0200579 gsn->ctrl = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_GGSN, NULL);
580 if (!gsn->ctrl) {
581 LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
582 exit(1);
583 }
584
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100585 /* skip the configuration of the tun0 if we're using the gtp0 device */
586 if (gtp_kernel_enabled())
587 goto skip_tun;
588
Harald Weltebed35df2011-11-02 13:06:18 +0100589 /* Create a tunnel interface */
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100590 DEBUGP(DGGSN, "Creating tun interface\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100591 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100592 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create tun");
Harald Weltebed35df2011-11-02 13:06:18 +0100593 exit(1);
594 }
jjakoa7cd2492003-04-11 09:40:12 +0000595
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100596 DEBUGP(DGGSN, "Setting tun IP address\n");
Harald Welted12eab92017-08-02 19:49:47 +0200597 if (tun_setaddr(tun, &netaddr, &destaddr, &prefixlen)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100598 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to set tun IP address");
Harald Weltebed35df2011-11-02 13:06:18 +0100599 exit(1);
600 }
jjakoa7cd2492003-04-11 09:40:12 +0000601
Harald Weltebed35df2011-11-02 13:06:18 +0100602 tun_set_cb_ind(tun, cb_tun_ind);
603 if (tun->fd > maxfd)
604 maxfd = tun->fd;
jjakoc6762cf2004-04-28 14:52:58 +0000605
Harald Weltebed35df2011-11-02 13:06:18 +0100606 if (ipup)
607 tun_runscript(tun, ipup);
jjako52c24142002-12-16 13:33:51 +0000608
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100609skip_tun:
610
jjako52c24142002-12-16 13:33:51 +0000611 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +0100612 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +0000613 /******************************************************************/
614
Harald Weltebed35df2011-11-02 13:06:18 +0100615 while ((((starttime + timelimit) > time(NULL)) || (0 == timelimit))
616 && (!end)) {
Harald Weltec3dcba02010-05-04 11:02:54 +0200617
Harald Weltebed35df2011-11-02 13:06:18 +0100618 FD_ZERO(&fds);
619 if (tun)
620 FD_SET(tun->fd, &fds);
621 FD_SET(gsn->fd0, &fds);
622 FD_SET(gsn->fd1c, &fds);
623 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +0000624
Harald Weltebed35df2011-11-02 13:06:18 +0100625 gtp_retranstimeout(gsn, &idleTime);
626 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
627 case -1: /* errno == EINTR : unblocked signal */
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100628 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100629 "select() returned -1");
630 /* On error, select returns without modifying fds */
631 FD_ZERO(&fds);
632 break;
633 case 0:
634 /* printf("Select returned 0\n"); */
635 gtp_retrans(gsn); /* Only retransmit if nothing else */
636 break;
637 default:
638 break;
639 }
jjako52c24142002-12-16 13:33:51 +0000640
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100641 if (tun && tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
Harald Weltebed35df2011-11-02 13:06:18 +0100642 tun_decaps(tun) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100643 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100644 "TUN read failed (fd)=(%d)", tun->fd);
645 }
646
647 if (FD_ISSET(gsn->fd0, &fds))
648 gtp_decaps0(gsn);
649
650 if (FD_ISSET(gsn->fd1c, &fds))
651 gtp_decaps1c(gsn);
652
653 if (FD_ISSET(gsn->fd1u, &fds))
654 gtp_decaps1u(gsn);
655
Max727417d2016-08-02 17:10:38 +0200656 osmo_select_main(1);
Harald Weltebed35df2011-11-02 13:06:18 +0100657 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100658err:
659 gtp_kernel_stop();
Harald Weltebed35df2011-11-02 13:06:18 +0100660 cmdline_parser_free(&args_info);
661 ippool_free(ippool);
662 gtp_free(gsn);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100663 if (tun)
664 tun_free(tun);
Harald Weltebed35df2011-11-02 13:06:18 +0100665
666 return 1;
667
jjako52c24142002-12-16 13:33:51 +0000668}