blob: 9b118840b5a8dd76365050cbd022ee91b8cb25e4 [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) {
Harald Welted4d6e092017-08-08 18:10:43 +0200244 /* Due to the fact that 3GPP requires an allocation of a
245 * /64 prefix to each MS, we must instruct
246 * ippool_getip() below to match only the leading /64
247 * prefix, i.e. the first 8 bytes of the address */
248 dst.len = 8;
Harald Weltea0d281d2017-08-02 21:48:16 +0200249 dst.v6 = ip6h->ip6_dst;
Harald Welted12eab92017-08-02 19:49:47 +0200250 } else {
Harald Weltea0d281d2017-08-02 21:48:16 +0200251 LOGP(DGGSN, LOGL_NOTICE, "non-IPv packet received from tun\n");
Harald Welted12eab92017-08-02 19:49:47 +0200252 return -1;
253 }
jjakoc6762cf2004-04-28 14:52:58 +0000254
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100255 DEBUGP(DGGSN, "Received packet from tun!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100256
257 if (ippool_getip(ippool, &ipm, &dst)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100258 DEBUGP(DGGSN, "Received packet with no destination!!!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100259 return 0;
260 }
261
262 if (ipm->peer) /* Check if a peer protocol is defined */
263 gtp_data_req(gsn, (struct pdp_t *)ipm->peer, pack, len);
264 return 0;
jjako52c24142002-12-16 13:33:51 +0000265}
266
Harald Weltebed35df2011-11-02 13:06:18 +0100267int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
268{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100269 DEBUGP(DGGSN, "encaps_tun. Packet received: forwarding to tun\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100270 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000271}
272
jjako52c24142002-12-16 13:33:51 +0000273int main(int argc, char **argv)
274{
Harald Weltebed35df2011-11-02 13:06:18 +0100275 /* gengeopt declarations */
276 struct gengetopt_args_info args_info;
jjako52c24142002-12-16 13:33:51 +0000277
Harald Weltebed35df2011-11-02 13:06:18 +0100278 struct hostent *host;
jjako52c24142002-12-16 13:33:51 +0000279
Harald Weltebed35df2011-11-02 13:06:18 +0100280 /* Handle keyboard interrupt SIGINT */
281 struct sigaction s;
282 s.sa_handler = (void *)signal_handler;
283 if ((0 != sigemptyset(&s.sa_mask)) && debug)
284 printf("sigemptyset failed.\n");
285 s.sa_flags = SA_RESETHAND;
286 if ((sigaction(SIGINT, &s, NULL) != 0) && debug)
287 printf("Could not register SIGINT signal handler.\n");
jjako52c24142002-12-16 13:33:51 +0000288
Harald Weltebed35df2011-11-02 13:06:18 +0100289 fd_set fds; /* For select() */
290 struct timeval idleTime; /* How long to select() */
jjako52c24142002-12-16 13:33:51 +0000291
Harald Weltebed35df2011-11-02 13:06:18 +0100292 int timelimit; /* Number of seconds to be connected */
293 int starttime; /* Time program was started */
jjako52c24142002-12-16 13:33:51 +0000294
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100295 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +0000296
Harald Weltebed35df2011-11-02 13:06:18 +0100297 if (cmdline_parser(argc, argv, &args_info) != 0)
298 exit(1);
299 if (args_info.debug_flag) {
300 printf("listen: %s\n", args_info.listen_arg);
301 if (args_info.conf_arg)
302 printf("conf: %s\n", args_info.conf_arg);
303 printf("fg: %d\n", args_info.fg_flag);
304 printf("debug: %d\n", args_info.debug_flag);
305 printf("qos: %#08x\n", args_info.qos_arg);
306 if (args_info.apn_arg)
307 printf("apn: %s\n", args_info.apn_arg);
308 if (args_info.net_arg)
309 printf("net: %s\n", args_info.net_arg);
310 if (args_info.dynip_arg)
311 printf("dynip: %s\n", args_info.dynip_arg);
312 if (args_info.statip_arg)
313 printf("statip: %s\n", args_info.statip_arg);
314 if (args_info.ipup_arg)
315 printf("ipup: %s\n", args_info.ipup_arg);
316 if (args_info.ipdown_arg)
317 printf("ipdown: %s\n", args_info.ipdown_arg);
318 if (args_info.pidfile_arg)
319 printf("pidfile: %s\n", args_info.pidfile_arg);
320 if (args_info.statedir_arg)
321 printf("statedir: %s\n", args_info.statedir_arg);
Pablo Neira Ayusod9d7be32016-05-10 18:43:12 +0200322 if (args_info.gtp_linux_flag)
323 printf("gtp_linux: %d\n", args_info.gtp_linux_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100324 printf("timelimit: %d\n", args_info.timelimit_arg);
325 }
jjako52c24142002-12-16 13:33:51 +0000326
Harald Weltebed35df2011-11-02 13:06:18 +0100327 /* Try out our new parser */
jjako52c24142002-12-16 13:33:51 +0000328
Harald Weltebed35df2011-11-02 13:06:18 +0100329 if (cmdline_parser_configfile(args_info.conf_arg, &args_info, 0, 0, 0)
330 != 0)
331 exit(1);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100332
333 /* Open a log file */
334 if (args_info.logfile_arg) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100335 struct log_target *tgt;
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100336 int lvl;
337
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100338 tgt = log_target_find(LOG_TGT_TYPE_FILE, args_info.logfile_arg);
339 if (!tgt) {
340 tgt = log_target_create_file(args_info.logfile_arg);
341 if (!tgt) {
342 LOGP(DGGSN, LOGL_ERROR,
343 "Failed to create logfile: %s\n",
344 args_info.logfile_arg);
345 exit(1);
346 }
347 log_add_target(tgt);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100348 }
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100349 log_set_all_filter(tgt, 1);
350 log_set_use_color(tgt, 0);
351
352 if (args_info.loglevel_arg) {
353 lvl = log_parse_level(args_info.loglevel_arg);
354 log_set_log_level(tgt, lvl);
355 LOGP(DGGSN, LOGL_NOTICE,
356 "Set file log level to %s\n",
357 log_level_str(lvl));
358 }
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100359 }
360
Harald Weltebed35df2011-11-02 13:06:18 +0100361 if (args_info.debug_flag) {
362 printf("cmdline_parser_configfile\n");
363 printf("listen: %s\n", args_info.listen_arg);
364 printf("conf: %s\n", args_info.conf_arg);
365 printf("fg: %d\n", args_info.fg_flag);
366 printf("debug: %d\n", args_info.debug_flag);
367 printf("qos: %#08x\n", args_info.qos_arg);
368 if (args_info.apn_arg)
369 printf("apn: %s\n", args_info.apn_arg);
370 if (args_info.net_arg)
371 printf("net: %s\n", args_info.net_arg);
372 if (args_info.dynip_arg)
373 printf("dynip: %s\n", args_info.dynip_arg);
374 if (args_info.statip_arg)
375 printf("statip: %s\n", args_info.statip_arg);
376 if (args_info.ipup_arg)
377 printf("ipup: %s\n", args_info.ipup_arg);
378 if (args_info.ipdown_arg)
379 printf("ipdown: %s\n", args_info.ipdown_arg);
380 if (args_info.pidfile_arg)
381 printf("pidfile: %s\n", args_info.pidfile_arg);
382 if (args_info.statedir_arg)
383 printf("statedir: %s\n", args_info.statedir_arg);
Pablo Neira Ayusod9d7be32016-05-10 18:43:12 +0200384 if (args_info.gtp_linux_flag)
385 printf("gtp-linux: %d\n", args_info.gtp_linux_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100386 printf("timelimit: %d\n", args_info.timelimit_arg);
387 }
jjako52c24142002-12-16 13:33:51 +0000388
Harald Weltebed35df2011-11-02 13:06:18 +0100389 /* Handle each option */
jjako52c24142002-12-16 13:33:51 +0000390
Harald Weltebed35df2011-11-02 13:06:18 +0100391 /* debug */
392 debug = args_info.debug_flag;
jjako52c24142002-12-16 13:33:51 +0000393
Harald Weltebed35df2011-11-02 13:06:18 +0100394 /* listen */
395 /* Do hostname lookup to translate hostname to IP address */
396 /* Any port listening is not possible as a valid address is */
397 /* required for create_pdp_context_response messages */
398 if (args_info.listen_arg) {
399 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100400 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100401 "Invalid listening address: %s!",
402 args_info.listen_arg);
403 exit(1);
404 } else {
405 memcpy(&listen_.s_addr, host->h_addr, host->h_length);
406 }
407 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100408 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100409 "Listening address must be specified! "
410 "Please use command line option --listen or "
411 "edit %s configuration file\n", args_info.conf_arg);
412 exit(1);
413 }
jjako88c22162003-07-06 19:33:18 +0000414
Harald Weltebed35df2011-11-02 13:06:18 +0100415 /* net */
416 /* Store net as in_addr net and mask */
417 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200418 struct in46_addr in46;
419 if (ippool_aton(&in46, &prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100420 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100421 "Invalid network address: %s!",
422 args_info.net_arg);
423 exit(1);
424 }
Harald Welted12eab92017-08-02 19:49:47 +0200425 net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100426 netaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
427 destaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
428 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100429 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100430 "Network address must be specified: %s!",
431 args_info.net_arg);
432 exit(1);
433 }
jjako52c24142002-12-16 13:33:51 +0000434
Harald Weltebed35df2011-11-02 13:06:18 +0100435 /* dynip */
436 if (!args_info.dynip_arg) {
437 if (ippool_new(&ippool, args_info.net_arg, NULL, 1, 0,
438 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
439 IPPOOL_NOBROADCAST)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100440 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100441 "Failed to allocate IP pool!");
442 exit(1);
443 }
444 } else {
445 if (ippool_new(&ippool, args_info.dynip_arg, NULL, 1, 0,
446 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
447 IPPOOL_NOBROADCAST)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100448 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100449 "Failed to allocate IP pool!");
450 exit(1);
451 }
452 }
jjako52c24142002-12-16 13:33:51 +0000453
Harald Weltebed35df2011-11-02 13:06:18 +0100454 /* DNS1 and DNS2 */
jjakoff9985c2004-01-16 11:05:22 +0000455#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +0100456 dns1.s_addr = 0;
457 if (args_info.pcodns1_arg) {
458 if (0 == inet_aton(args_info.pcodns1_arg, &dns1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100459 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100460 "Failed to convert pcodns1!");
461 exit(1);
462 }
463 }
464 dns2.s_addr = 0;
465 if (args_info.pcodns2_arg) {
466 if (0 == inet_aton(args_info.pcodns2_arg, &dns2)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100467 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100468 "Failed to convert pcodns2!");
469 exit(1);
470 }
471 }
jjako1d3db972004-01-16 09:56:56 +0000472#else
Harald Weltebed35df2011-11-02 13:06:18 +0100473 dns1.s_addr = 0;
474 if (args_info.pcodns1_arg) {
475 dns1.s_addr = inet_addr(args_info.pcodns1_arg);
476 if (dns1.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100477 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100478 "Failed to convert pcodns1!");
479 exit(1);
480 }
481 }
482 dns2.s_addr = 0;
483 if (args_info.pcodns2_arg) {
484 dns2.s_addr = inet_addr(args_info.pcodns2_arg);
485 if (dns2.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100486 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100487 "Failed to convert pcodns2!");
488 exit(1);
489 }
490 }
jjako1d3db972004-01-16 09:56:56 +0000491#endif
492
Harald Weltebed35df2011-11-02 13:06:18 +0100493 pco.l = 20;
494 pco.v[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
495 pco.v[1] = 0x80; /* IPCP */
496 pco.v[2] = 0x21;
497 pco.v[3] = 0x10; /* Length of contents */
498 pco.v[4] = 0x02; /* ACK */
499 pco.v[5] = 0x00; /* ID: Need to match request */
500 pco.v[6] = 0x00; /* Length */
501 pco.v[7] = 0x10;
502 pco.v[8] = 0x81; /* DNS 1 */
503 pco.v[9] = 0x06;
504 memcpy(&pco.v[10], &dns1, sizeof(dns1));
505 pco.v[14] = 0x83;
506 pco.v[15] = 0x06; /* DNS 2 */
507 memcpy(&pco.v[16], &dns2, sizeof(dns2));
jjakoa7cd2492003-04-11 09:40:12 +0000508
Harald Weltebed35df2011-11-02 13:06:18 +0100509 /* ipup */
510 ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000511
Harald Weltebed35df2011-11-02 13:06:18 +0100512 /* ipdown */
513 ipdown = args_info.ipdown_arg;
jjako4b26b512003-01-28 16:13:57 +0000514
Harald Weltebed35df2011-11-02 13:06:18 +0100515 /* Timelimit */
516 timelimit = args_info.timelimit_arg;
517 starttime = time(NULL);
jjako4b26b512003-01-28 16:13:57 +0000518
Harald Weltebed35df2011-11-02 13:06:18 +0100519 /* qos */
520 qos.l = 3;
521 qos.v[2] = (args_info.qos_arg) & 0xff;
522 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
523 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
jjakoa7cd2492003-04-11 09:40:12 +0000524
Harald Weltebed35df2011-11-02 13:06:18 +0100525 /* apn */
526 if (strlen(args_info.apn_arg) > (sizeof(apn.v) - 1)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100527 LOGP(DGGSN, LOGL_ERROR, "Invalid APN\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100528 return -1;
529 }
530 apn.l = strlen(args_info.apn_arg) + 1;
531 apn.v[0] = (char)strlen(args_info.apn_arg);
532 strncpy((char *)&apn.v[1], args_info.apn_arg, sizeof(apn.v) - 1);
jjakoe0149782003-07-06 17:07:04 +0000533
Harald Weltebed35df2011-11-02 13:06:18 +0100534 /* foreground */
535 /* If flag not given run as a daemon */
536 if (!args_info.fg_flag) {
537 FILE *f;
538 int rc;
Harald Weltebed35df2011-11-02 13:06:18 +0100539 /* Close the standard file descriptors. */
540 /* Is this really needed ? */
541 f = freopen("/dev/null", "w", stdout);
542 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100543 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100544 "Could not redirect stdout to /dev/null");
545 }
546 f = freopen("/dev/null", "w", stderr);
547 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100548 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100549 "Could not redirect stderr to /dev/null");
550 }
551 f = freopen("/dev/null", "r", stdin);
552 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100553 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100554 "Could not redirect stdin to /dev/null");
555 }
556 rc = daemon(0, 0);
557 if (rc != 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100558 SYS_ERR(DGGSN, LOGL_ERROR, rc,
Harald Weltebed35df2011-11-02 13:06:18 +0100559 "Could not daemonize");
560 exit(1);
561 }
Harald Weltebed35df2011-11-02 13:06:18 +0100562 }
jjakoe0149782003-07-06 17:07:04 +0000563
Harald Weltebed35df2011-11-02 13:06:18 +0100564 /* pidfile */
565 /* This has to be done after we have our final pid */
566 if (args_info.pidfile_arg) {
567 log_pid(args_info.pidfile_arg);
568 }
jjakoe0149782003-07-06 17:07:04 +0000569
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100570 DEBUGP(DGGSN, "gtpclient: Initialising GTP tunnel\n");
jjako52c24142002-12-16 13:33:51 +0000571
Harald Weltebed35df2011-11-02 13:06:18 +0100572 if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100573 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +0100574 exit(1);
575 }
576 if (gsn->fd0 > maxfd)
577 maxfd = gsn->fd0;
578 if (gsn->fd1c > maxfd)
579 maxfd = gsn->fd1c;
580 if (gsn->fd1u > maxfd)
581 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +0000582
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100583 /* use GTP kernel module for data packet encapsulation */
Harald Welted12eab92017-08-02 19:49:47 +0200584 if (gtp_kernel_init(gsn, &net, prefixlen, &args_info) < 0)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100585 goto err;
586
Harald Weltebed35df2011-11-02 13:06:18 +0100587 gtp_set_cb_data_ind(gsn, encaps_tun);
588 gtp_set_cb_delete_context(gsn, delete_context);
589 gtp_set_cb_create_context_ind(gsn, create_context_ind);
jjakoa7cd2492003-04-11 09:40:12 +0000590
Max727417d2016-08-02 17:10:38 +0200591 gsn->ctrl = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_GGSN, NULL);
592 if (!gsn->ctrl) {
593 LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
594 exit(1);
595 }
596
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100597 /* skip the configuration of the tun0 if we're using the gtp0 device */
598 if (gtp_kernel_enabled())
599 goto skip_tun;
600
Harald Weltebed35df2011-11-02 13:06:18 +0100601 /* Create a tunnel interface */
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100602 DEBUGP(DGGSN, "Creating tun interface\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100603 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100604 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create tun");
Harald Weltebed35df2011-11-02 13:06:18 +0100605 exit(1);
606 }
jjakoa7cd2492003-04-11 09:40:12 +0000607
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100608 DEBUGP(DGGSN, "Setting tun IP address\n");
Harald Welted12eab92017-08-02 19:49:47 +0200609 if (tun_setaddr(tun, &netaddr, &destaddr, &prefixlen)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100610 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to set tun IP address");
Harald Weltebed35df2011-11-02 13:06:18 +0100611 exit(1);
612 }
jjakoa7cd2492003-04-11 09:40:12 +0000613
Harald Weltebed35df2011-11-02 13:06:18 +0100614 tun_set_cb_ind(tun, cb_tun_ind);
615 if (tun->fd > maxfd)
616 maxfd = tun->fd;
jjakoc6762cf2004-04-28 14:52:58 +0000617
Harald Weltebed35df2011-11-02 13:06:18 +0100618 if (ipup)
619 tun_runscript(tun, ipup);
jjako52c24142002-12-16 13:33:51 +0000620
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100621skip_tun:
622
jjako52c24142002-12-16 13:33:51 +0000623 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +0100624 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +0000625 /******************************************************************/
626
Harald Weltebed35df2011-11-02 13:06:18 +0100627 while ((((starttime + timelimit) > time(NULL)) || (0 == timelimit))
628 && (!end)) {
Harald Weltec3dcba02010-05-04 11:02:54 +0200629
Harald Weltebed35df2011-11-02 13:06:18 +0100630 FD_ZERO(&fds);
631 if (tun)
632 FD_SET(tun->fd, &fds);
633 FD_SET(gsn->fd0, &fds);
634 FD_SET(gsn->fd1c, &fds);
635 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +0000636
Harald Weltebed35df2011-11-02 13:06:18 +0100637 gtp_retranstimeout(gsn, &idleTime);
638 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
639 case -1: /* errno == EINTR : unblocked signal */
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100640 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100641 "select() returned -1");
642 /* On error, select returns without modifying fds */
643 FD_ZERO(&fds);
644 break;
645 case 0:
646 /* printf("Select returned 0\n"); */
647 gtp_retrans(gsn); /* Only retransmit if nothing else */
648 break;
649 default:
650 break;
651 }
jjako52c24142002-12-16 13:33:51 +0000652
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100653 if (tun && tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
Harald Weltebed35df2011-11-02 13:06:18 +0100654 tun_decaps(tun) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100655 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100656 "TUN read failed (fd)=(%d)", tun->fd);
657 }
658
659 if (FD_ISSET(gsn->fd0, &fds))
660 gtp_decaps0(gsn);
661
662 if (FD_ISSET(gsn->fd1c, &fds))
663 gtp_decaps1c(gsn);
664
665 if (FD_ISSET(gsn->fd1u, &fds))
666 gtp_decaps1u(gsn);
667
Max727417d2016-08-02 17:10:38 +0200668 osmo_select_main(1);
Harald Weltebed35df2011-11-02 13:06:18 +0100669 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100670err:
671 gtp_kernel_stop();
Harald Weltebed35df2011-11-02 13:06:18 +0100672 cmdline_parser_free(&args_info);
673 ippool_free(ippool);
674 gtp_free(gsn);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100675 if (tun)
676 tun_free(tun);
Harald Weltebed35df2011-11-02 13:06:18 +0100677
678 return 1;
679
jjako52c24142002-12-16 13:33:51 +0000680}