blob: 0629f9e7e5fa15a90cbe0e690ec3f7c38538bcf7 [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;
Harald Welted1bf1e12017-08-03 00:00:23 +0200181 int rc;
jjako52c24142002-12-16 13:33:51 +0000182
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100183 DEBUGP(DGGSN, "Received create PDP context request\n");
jjako52c24142002-12-16 13:33:51 +0000184
Harald Welted9d88622017-08-04 00:22:35 +0200185 /* FIXME: we manually force all context requests to dynamic here! */
186 if (pdp->eua.l > 2)
187 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +0000188
Harald Weltebed35df2011-11-02 13:06:18 +0100189 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
190 memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg));
jjako52c24142002-12-16 13:33:51 +0000191
Harald Weltebed35df2011-11-02 13:06:18 +0100192 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
193 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000194
Harald Weltea0d281d2017-08-02 21:48:16 +0200195 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Welted1bf1e12017-08-03 00:00:23 +0200196 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Cannot decode EUA from MS/SGSN: %s",
197 osmo_hexdump(pdp->eua.v, pdp->eua.l));
198 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
199 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100200 }
jjakoa7cd2492003-04-11 09:40:12 +0000201
Harald Welted1bf1e12017-08-03 00:00:23 +0200202 rc = ippool_newip(ippool, &member, &addr, 0);
203 if (rc < 0) {
204 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Cannot allocate IP address in pool\n");
205 gtp_create_context_resp(gsn, pdp, -rc);
Harald Weltebed35df2011-11-02 13:06:18 +0100206 return 0; /* Allready in use, or no more available */
207 }
jjakoa7cd2492003-04-11 09:40:12 +0000208
Harald Weltea0d281d2017-08-02 21:48:16 +0200209 in46a_to_eua(&member->addr, &pdp->eua);
Harald Weltebed35df2011-11-02 13:06:18 +0100210 pdp->peer = member;
211 pdp->ipif = tun; /* TODO */
212 member->peer = pdp;
jjako52c24142002-12-16 13:33:51 +0000213
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100214 if (gtp_kernel_tunnel_add(pdp) < 0) {
Andreas Schultzc5fbf9b2015-11-17 12:22:43 +0100215 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100216 "Cannot add tunnel to kernel: %s\n", strerror(errno));
Harald Welted1bf1e12017-08-03 00:00:23 +0200217 gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
218 return 0;
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100219 }
Max3142d8d2017-05-04 17:45:10 +0200220
221 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200222 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
223 return 0;
224 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100225
Harald Weltebed35df2011-11-02 13:06:18 +0100226 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
227 return 0; /* Success */
jjako52c24142002-12-16 13:33:51 +0000228}
229
jjakoa7cd2492003-04-11 09:40:12 +0000230/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +0100231int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
232{
233 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200234 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200235 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200236 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoc6762cf2004-04-28 14:52:58 +0000237
Harald Welte63ebccd2017-08-02 21:10:09 +0200238 if (iph->version == 4) {
Harald Welted12eab92017-08-02 19:49:47 +0200239 if (len < sizeof(*iph) || len < 4*iph->ihl)
240 return -1;
241 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200242 dst.v4.s_addr = iph->daddr;
Harald Weltea0d281d2017-08-02 21:48:16 +0200243 } else if (iph->version == 6) {
244 dst.len = 16;
245 dst.v6 = ip6h->ip6_dst;
Harald Welted12eab92017-08-02 19:49:47 +0200246 } else {
Harald Weltea0d281d2017-08-02 21:48:16 +0200247 LOGP(DGGSN, LOGL_NOTICE, "non-IPv packet received from tun\n");
Harald Welted12eab92017-08-02 19:49:47 +0200248 return -1;
249 }
jjakoc6762cf2004-04-28 14:52:58 +0000250
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100251 DEBUGP(DGGSN, "Received packet from tun!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100252
253 if (ippool_getip(ippool, &ipm, &dst)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100254 DEBUGP(DGGSN, "Received packet with no destination!!!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100255 return 0;
256 }
257
258 if (ipm->peer) /* Check if a peer protocol is defined */
259 gtp_data_req(gsn, (struct pdp_t *)ipm->peer, pack, len);
260 return 0;
jjako52c24142002-12-16 13:33:51 +0000261}
262
Harald Weltebed35df2011-11-02 13:06:18 +0100263int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
264{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100265 DEBUGP(DGGSN, "encaps_tun. Packet received: forwarding to tun\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100266 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000267}
268
jjako52c24142002-12-16 13:33:51 +0000269int main(int argc, char **argv)
270{
Harald Weltebed35df2011-11-02 13:06:18 +0100271 /* gengeopt declarations */
272 struct gengetopt_args_info args_info;
jjako52c24142002-12-16 13:33:51 +0000273
Harald Weltebed35df2011-11-02 13:06:18 +0100274 struct hostent *host;
jjako52c24142002-12-16 13:33:51 +0000275
Harald Weltebed35df2011-11-02 13:06:18 +0100276 /* Handle keyboard interrupt SIGINT */
277 struct sigaction s;
278 s.sa_handler = (void *)signal_handler;
279 if ((0 != sigemptyset(&s.sa_mask)) && debug)
280 printf("sigemptyset failed.\n");
281 s.sa_flags = SA_RESETHAND;
282 if ((sigaction(SIGINT, &s, NULL) != 0) && debug)
283 printf("Could not register SIGINT signal handler.\n");
jjako52c24142002-12-16 13:33:51 +0000284
Harald Weltebed35df2011-11-02 13:06:18 +0100285 fd_set fds; /* For select() */
286 struct timeval idleTime; /* How long to select() */
jjako52c24142002-12-16 13:33:51 +0000287
Harald Weltebed35df2011-11-02 13:06:18 +0100288 int timelimit; /* Number of seconds to be connected */
289 int starttime; /* Time program was started */
jjako52c24142002-12-16 13:33:51 +0000290
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100291 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +0000292
Harald Weltebed35df2011-11-02 13:06:18 +0100293 if (cmdline_parser(argc, argv, &args_info) != 0)
294 exit(1);
295 if (args_info.debug_flag) {
296 printf("listen: %s\n", args_info.listen_arg);
297 if (args_info.conf_arg)
298 printf("conf: %s\n", args_info.conf_arg);
299 printf("fg: %d\n", args_info.fg_flag);
300 printf("debug: %d\n", args_info.debug_flag);
301 printf("qos: %#08x\n", args_info.qos_arg);
302 if (args_info.apn_arg)
303 printf("apn: %s\n", args_info.apn_arg);
304 if (args_info.net_arg)
305 printf("net: %s\n", args_info.net_arg);
306 if (args_info.dynip_arg)
307 printf("dynip: %s\n", args_info.dynip_arg);
308 if (args_info.statip_arg)
309 printf("statip: %s\n", args_info.statip_arg);
310 if (args_info.ipup_arg)
311 printf("ipup: %s\n", args_info.ipup_arg);
312 if (args_info.ipdown_arg)
313 printf("ipdown: %s\n", args_info.ipdown_arg);
314 if (args_info.pidfile_arg)
315 printf("pidfile: %s\n", args_info.pidfile_arg);
316 if (args_info.statedir_arg)
317 printf("statedir: %s\n", args_info.statedir_arg);
Pablo Neira Ayusod9d7be32016-05-10 18:43:12 +0200318 if (args_info.gtp_linux_flag)
319 printf("gtp_linux: %d\n", args_info.gtp_linux_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100320 printf("timelimit: %d\n", args_info.timelimit_arg);
321 }
jjako52c24142002-12-16 13:33:51 +0000322
Harald Weltebed35df2011-11-02 13:06:18 +0100323 /* Try out our new parser */
jjako52c24142002-12-16 13:33:51 +0000324
Harald Weltebed35df2011-11-02 13:06:18 +0100325 if (cmdline_parser_configfile(args_info.conf_arg, &args_info, 0, 0, 0)
326 != 0)
327 exit(1);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100328
329 /* Open a log file */
330 if (args_info.logfile_arg) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100331 struct log_target *tgt;
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100332 int lvl;
333
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100334 tgt = log_target_find(LOG_TGT_TYPE_FILE, args_info.logfile_arg);
335 if (!tgt) {
336 tgt = log_target_create_file(args_info.logfile_arg);
337 if (!tgt) {
338 LOGP(DGGSN, LOGL_ERROR,
339 "Failed to create logfile: %s\n",
340 args_info.logfile_arg);
341 exit(1);
342 }
343 log_add_target(tgt);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100344 }
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100345 log_set_all_filter(tgt, 1);
346 log_set_use_color(tgt, 0);
347
348 if (args_info.loglevel_arg) {
349 lvl = log_parse_level(args_info.loglevel_arg);
350 log_set_log_level(tgt, lvl);
351 LOGP(DGGSN, LOGL_NOTICE,
352 "Set file log level to %s\n",
353 log_level_str(lvl));
354 }
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100355 }
356
Harald Weltebed35df2011-11-02 13:06:18 +0100357 if (args_info.debug_flag) {
358 printf("cmdline_parser_configfile\n");
359 printf("listen: %s\n", args_info.listen_arg);
360 printf("conf: %s\n", args_info.conf_arg);
361 printf("fg: %d\n", args_info.fg_flag);
362 printf("debug: %d\n", args_info.debug_flag);
363 printf("qos: %#08x\n", args_info.qos_arg);
364 if (args_info.apn_arg)
365 printf("apn: %s\n", args_info.apn_arg);
366 if (args_info.net_arg)
367 printf("net: %s\n", args_info.net_arg);
368 if (args_info.dynip_arg)
369 printf("dynip: %s\n", args_info.dynip_arg);
370 if (args_info.statip_arg)
371 printf("statip: %s\n", args_info.statip_arg);
372 if (args_info.ipup_arg)
373 printf("ipup: %s\n", args_info.ipup_arg);
374 if (args_info.ipdown_arg)
375 printf("ipdown: %s\n", args_info.ipdown_arg);
376 if (args_info.pidfile_arg)
377 printf("pidfile: %s\n", args_info.pidfile_arg);
378 if (args_info.statedir_arg)
379 printf("statedir: %s\n", args_info.statedir_arg);
Pablo Neira Ayusod9d7be32016-05-10 18:43:12 +0200380 if (args_info.gtp_linux_flag)
381 printf("gtp-linux: %d\n", args_info.gtp_linux_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100382 printf("timelimit: %d\n", args_info.timelimit_arg);
383 }
jjako52c24142002-12-16 13:33:51 +0000384
Harald Weltebed35df2011-11-02 13:06:18 +0100385 /* Handle each option */
jjako52c24142002-12-16 13:33:51 +0000386
Harald Weltebed35df2011-11-02 13:06:18 +0100387 /* debug */
388 debug = args_info.debug_flag;
jjako52c24142002-12-16 13:33:51 +0000389
Harald Weltebed35df2011-11-02 13:06:18 +0100390 /* listen */
391 /* Do hostname lookup to translate hostname to IP address */
392 /* Any port listening is not possible as a valid address is */
393 /* required for create_pdp_context_response messages */
394 if (args_info.listen_arg) {
395 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100396 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100397 "Invalid listening address: %s!",
398 args_info.listen_arg);
399 exit(1);
400 } else {
401 memcpy(&listen_.s_addr, host->h_addr, host->h_length);
402 }
403 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100404 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100405 "Listening address must be specified! "
406 "Please use command line option --listen or "
407 "edit %s configuration file\n", args_info.conf_arg);
408 exit(1);
409 }
jjako88c22162003-07-06 19:33:18 +0000410
Harald Weltebed35df2011-11-02 13:06:18 +0100411 /* net */
412 /* Store net as in_addr net and mask */
413 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200414 struct in46_addr in46;
415 if (ippool_aton(&in46, &prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100416 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100417 "Invalid network address: %s!",
418 args_info.net_arg);
419 exit(1);
420 }
Harald Welted12eab92017-08-02 19:49:47 +0200421 net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100422 netaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
423 destaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
424 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100425 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100426 "Network address must be specified: %s!",
427 args_info.net_arg);
428 exit(1);
429 }
jjako52c24142002-12-16 13:33:51 +0000430
Harald Weltebed35df2011-11-02 13:06:18 +0100431 /* dynip */
432 if (!args_info.dynip_arg) {
433 if (ippool_new(&ippool, args_info.net_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 } else {
441 if (ippool_new(&ippool, args_info.dynip_arg, NULL, 1, 0,
442 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
443 IPPOOL_NOBROADCAST)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100444 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100445 "Failed to allocate IP pool!");
446 exit(1);
447 }
448 }
jjako52c24142002-12-16 13:33:51 +0000449
Harald Weltebed35df2011-11-02 13:06:18 +0100450 /* DNS1 and DNS2 */
jjakoff9985c2004-01-16 11:05:22 +0000451#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +0100452 dns1.s_addr = 0;
453 if (args_info.pcodns1_arg) {
454 if (0 == inet_aton(args_info.pcodns1_arg, &dns1)) {
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 pcodns1!");
457 exit(1);
458 }
459 }
460 dns2.s_addr = 0;
461 if (args_info.pcodns2_arg) {
462 if (0 == inet_aton(args_info.pcodns2_arg, &dns2)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100463 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100464 "Failed to convert pcodns2!");
465 exit(1);
466 }
467 }
jjako1d3db972004-01-16 09:56:56 +0000468#else
Harald Weltebed35df2011-11-02 13:06:18 +0100469 dns1.s_addr = 0;
470 if (args_info.pcodns1_arg) {
471 dns1.s_addr = inet_addr(args_info.pcodns1_arg);
472 if (dns1.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100473 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100474 "Failed to convert pcodns1!");
475 exit(1);
476 }
477 }
478 dns2.s_addr = 0;
479 if (args_info.pcodns2_arg) {
480 dns2.s_addr = inet_addr(args_info.pcodns2_arg);
481 if (dns2.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100482 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100483 "Failed to convert pcodns2!");
484 exit(1);
485 }
486 }
jjako1d3db972004-01-16 09:56:56 +0000487#endif
488
Harald Weltebed35df2011-11-02 13:06:18 +0100489 pco.l = 20;
490 pco.v[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
491 pco.v[1] = 0x80; /* IPCP */
492 pco.v[2] = 0x21;
493 pco.v[3] = 0x10; /* Length of contents */
494 pco.v[4] = 0x02; /* ACK */
495 pco.v[5] = 0x00; /* ID: Need to match request */
496 pco.v[6] = 0x00; /* Length */
497 pco.v[7] = 0x10;
498 pco.v[8] = 0x81; /* DNS 1 */
499 pco.v[9] = 0x06;
500 memcpy(&pco.v[10], &dns1, sizeof(dns1));
501 pco.v[14] = 0x83;
502 pco.v[15] = 0x06; /* DNS 2 */
503 memcpy(&pco.v[16], &dns2, sizeof(dns2));
jjakoa7cd2492003-04-11 09:40:12 +0000504
Harald Weltebed35df2011-11-02 13:06:18 +0100505 /* ipup */
506 ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000507
Harald Weltebed35df2011-11-02 13:06:18 +0100508 /* ipdown */
509 ipdown = args_info.ipdown_arg;
jjako4b26b512003-01-28 16:13:57 +0000510
Harald Weltebed35df2011-11-02 13:06:18 +0100511 /* Timelimit */
512 timelimit = args_info.timelimit_arg;
513 starttime = time(NULL);
jjako4b26b512003-01-28 16:13:57 +0000514
Harald Weltebed35df2011-11-02 13:06:18 +0100515 /* qos */
516 qos.l = 3;
517 qos.v[2] = (args_info.qos_arg) & 0xff;
518 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
519 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
jjakoa7cd2492003-04-11 09:40:12 +0000520
Harald Weltebed35df2011-11-02 13:06:18 +0100521 /* apn */
522 if (strlen(args_info.apn_arg) > (sizeof(apn.v) - 1)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100523 LOGP(DGGSN, LOGL_ERROR, "Invalid APN\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100524 return -1;
525 }
526 apn.l = strlen(args_info.apn_arg) + 1;
527 apn.v[0] = (char)strlen(args_info.apn_arg);
528 strncpy((char *)&apn.v[1], args_info.apn_arg, sizeof(apn.v) - 1);
jjakoe0149782003-07-06 17:07:04 +0000529
Harald Weltebed35df2011-11-02 13:06:18 +0100530 /* foreground */
531 /* If flag not given run as a daemon */
532 if (!args_info.fg_flag) {
533 FILE *f;
534 int rc;
Harald Weltebed35df2011-11-02 13:06:18 +0100535 /* Close the standard file descriptors. */
536 /* Is this really needed ? */
537 f = freopen("/dev/null", "w", stdout);
538 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100539 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100540 "Could not redirect stdout to /dev/null");
541 }
542 f = freopen("/dev/null", "w", stderr);
543 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100544 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100545 "Could not redirect stderr to /dev/null");
546 }
547 f = freopen("/dev/null", "r", stdin);
548 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100549 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100550 "Could not redirect stdin to /dev/null");
551 }
552 rc = daemon(0, 0);
553 if (rc != 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100554 SYS_ERR(DGGSN, LOGL_ERROR, rc,
Harald Weltebed35df2011-11-02 13:06:18 +0100555 "Could not daemonize");
556 exit(1);
557 }
Harald Weltebed35df2011-11-02 13:06:18 +0100558 }
jjakoe0149782003-07-06 17:07:04 +0000559
Harald Weltebed35df2011-11-02 13:06:18 +0100560 /* pidfile */
561 /* This has to be done after we have our final pid */
562 if (args_info.pidfile_arg) {
563 log_pid(args_info.pidfile_arg);
564 }
jjakoe0149782003-07-06 17:07:04 +0000565
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100566 DEBUGP(DGGSN, "gtpclient: Initialising GTP tunnel\n");
jjako52c24142002-12-16 13:33:51 +0000567
Harald Weltebed35df2011-11-02 13:06:18 +0100568 if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100569 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +0100570 exit(1);
571 }
572 if (gsn->fd0 > maxfd)
573 maxfd = gsn->fd0;
574 if (gsn->fd1c > maxfd)
575 maxfd = gsn->fd1c;
576 if (gsn->fd1u > maxfd)
577 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +0000578
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100579 /* use GTP kernel module for data packet encapsulation */
Harald Welted12eab92017-08-02 19:49:47 +0200580 if (gtp_kernel_init(gsn, &net, prefixlen, &args_info) < 0)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100581 goto err;
582
Harald Weltebed35df2011-11-02 13:06:18 +0100583 gtp_set_cb_data_ind(gsn, encaps_tun);
584 gtp_set_cb_delete_context(gsn, delete_context);
585 gtp_set_cb_create_context_ind(gsn, create_context_ind);
jjakoa7cd2492003-04-11 09:40:12 +0000586
Max727417d2016-08-02 17:10:38 +0200587 gsn->ctrl = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_GGSN, NULL);
588 if (!gsn->ctrl) {
589 LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
590 exit(1);
591 }
592
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100593 /* skip the configuration of the tun0 if we're using the gtp0 device */
594 if (gtp_kernel_enabled())
595 goto skip_tun;
596
Harald Weltebed35df2011-11-02 13:06:18 +0100597 /* Create a tunnel interface */
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100598 DEBUGP(DGGSN, "Creating tun interface\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100599 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100600 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create tun");
Harald Weltebed35df2011-11-02 13:06:18 +0100601 exit(1);
602 }
jjakoa7cd2492003-04-11 09:40:12 +0000603
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100604 DEBUGP(DGGSN, "Setting tun IP address\n");
Harald Welted12eab92017-08-02 19:49:47 +0200605 if (tun_setaddr(tun, &netaddr, &destaddr, &prefixlen)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100606 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to set tun IP address");
Harald Weltebed35df2011-11-02 13:06:18 +0100607 exit(1);
608 }
jjakoa7cd2492003-04-11 09:40:12 +0000609
Harald Weltebed35df2011-11-02 13:06:18 +0100610 tun_set_cb_ind(tun, cb_tun_ind);
611 if (tun->fd > maxfd)
612 maxfd = tun->fd;
jjakoc6762cf2004-04-28 14:52:58 +0000613
Harald Weltebed35df2011-11-02 13:06:18 +0100614 if (ipup)
615 tun_runscript(tun, ipup);
jjako52c24142002-12-16 13:33:51 +0000616
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100617skip_tun:
618
jjako52c24142002-12-16 13:33:51 +0000619 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +0100620 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +0000621 /******************************************************************/
622
Harald Weltebed35df2011-11-02 13:06:18 +0100623 while ((((starttime + timelimit) > time(NULL)) || (0 == timelimit))
624 && (!end)) {
Harald Weltec3dcba02010-05-04 11:02:54 +0200625
Harald Weltebed35df2011-11-02 13:06:18 +0100626 FD_ZERO(&fds);
627 if (tun)
628 FD_SET(tun->fd, &fds);
629 FD_SET(gsn->fd0, &fds);
630 FD_SET(gsn->fd1c, &fds);
631 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +0000632
Harald Weltebed35df2011-11-02 13:06:18 +0100633 gtp_retranstimeout(gsn, &idleTime);
634 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
635 case -1: /* errno == EINTR : unblocked signal */
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100636 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100637 "select() returned -1");
638 /* On error, select returns without modifying fds */
639 FD_ZERO(&fds);
640 break;
641 case 0:
642 /* printf("Select returned 0\n"); */
643 gtp_retrans(gsn); /* Only retransmit if nothing else */
644 break;
645 default:
646 break;
647 }
jjako52c24142002-12-16 13:33:51 +0000648
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100649 if (tun && tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
Harald Weltebed35df2011-11-02 13:06:18 +0100650 tun_decaps(tun) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100651 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100652 "TUN read failed (fd)=(%d)", tun->fd);
653 }
654
655 if (FD_ISSET(gsn->fd0, &fds))
656 gtp_decaps0(gsn);
657
658 if (FD_ISSET(gsn->fd1c, &fds))
659 gtp_decaps1c(gsn);
660
661 if (FD_ISSET(gsn->fd1u, &fds))
662 gtp_decaps1u(gsn);
663
Max727417d2016-08-02 17:10:38 +0200664 osmo_select_main(1);
Harald Weltebed35df2011-11-02 13:06:18 +0100665 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100666err:
667 gtp_kernel_stop();
Harald Weltebed35df2011-11-02 13:06:18 +0100668 cmdline_parser_free(&args_info);
669 ippool_free(ippool);
670 gtp_free(gsn);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100671 if (tun)
672 tun_free(tun);
Harald Weltebed35df2011-11-02 13:06:18 +0100673
674 return 1;
675
jjako52c24142002-12-16 13:33:51 +0000676}