blob: c307177d8abc6783bc568135f278aefc022a128e [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"
Harald Welted46bcd22017-08-08 23:27:22 +020067#include "icmpv6.h"
jjako52c24142002-12-16 13:33:51 +000068
Harald Weltec3dcba02010-05-04 11:02:54 +020069int end = 0;
Harald Weltebed35df2011-11-02 13:06:18 +010070int maxfd = 0; /* For select() */
jjakoa7cd2492003-04-11 09:40:12 +000071
72struct in_addr listen_;
Harald Welted12eab92017-08-02 19:49:47 +020073struct in_addr netaddr, destaddr, net; /* Network interface */
74size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +010075struct in_addr dns1, dns2; /* PCO DNS address */
76char *ipup, *ipdown; /* Filename of scripts */
77int debug; /* Print debug output */
jjakoa7cd2492003-04-11 09:40:12 +000078struct ul255_t pco;
79struct ul255_t qos;
80struct ul255_t apn;
81
Harald Weltebed35df2011-11-02 13:06:18 +010082struct gsn_t *gsn; /* GSN instance */
83struct tun_t *tun; /* TUN instance */
84struct ippool_t *ippool; /* Pool of IP addresses */
jjako52c24142002-12-16 13:33:51 +000085
Harald Weltec3dcba02010-05-04 11:02:54 +020086/* To exit gracefully. Used with GCC compilation flag -pg and gprof */
Harald Weltebed35df2011-11-02 13:06:18 +010087void signal_handler(int s)
88{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +010089 DEBUGP(DGGSN, "Received signal %d, exiting.\n", s);
Harald Weltebed35df2011-11-02 13:06:18 +010090 end = 1;
Harald Weltec3dcba02010-05-04 11:02:54 +020091}
jjako52c24142002-12-16 13:33:51 +000092
93/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +010094void log_pid(char *pidfile)
95{
96 FILE *file;
97 mode_t oldmask;
98
99 oldmask = umask(022);
100 file = fopen(pidfile, "w");
101 umask(oldmask);
102 if (!file) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100103 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100104 "Failed to create process ID file: %s!", pidfile);
105 return;
106 }
107 fprintf(file, "%d\n", (int)getpid());
108 fclose(file);
jjako52c24142002-12-16 13:33:51 +0000109}
110
jjakobd937b72004-12-30 16:22:42 +0000111#if defined(__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100112int daemon(int nochdir, int noclose)
113{
114 int fd;
jjako0141d202004-01-09 15:19:20 +0000115
Harald Weltebed35df2011-11-02 13:06:18 +0100116 switch (fork()) {
117 case -1:
118 return (-1);
119 case 0:
120 break;
121 default:
122 _exit(0);
123 }
jjako0141d202004-01-09 15:19:20 +0000124
Harald Weltebed35df2011-11-02 13:06:18 +0100125 if (setsid() == -1)
126 return (-1);
jjako0141d202004-01-09 15:19:20 +0000127
Harald Weltebed35df2011-11-02 13:06:18 +0100128 if (!nochdir)
129 chdir("/");
130
131 if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
132 dup2(fd, STDIN_FILENO);
133 dup2(fd, STDOUT_FILENO);
134 dup2(fd, STDERR_FILENO);
135 if (fd > 2)
136 close(fd);
137 }
138 return (0);
jjako0141d202004-01-09 15:19:20 +0000139}
140#endif
141
Max3142d8d2017-05-04 17:45:10 +0200142static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const struct ippoolm_t *member, const char *var)
143{
Harald Welted12eab92017-08-02 19:49:47 +0200144 char addrbuf[256];
Max3142d8d2017-05-04 17:45:10 +0200145 char val[NAMESIZE];
146
Harald Welted12eab92017-08-02 19:49:47 +0200147 const char *addrstr = in46a_ntop(&member->addr, addrbuf, sizeof(addrbuf));
148
149 snprintf(val, sizeof(val), "%" PRIu64 ",%s", pdp->imsi, addrstr);
Max3142d8d2017-05-04 17:45:10 +0200150
151 if (ctrl_cmd_send_trap(gsn->ctrl, var, val) < 0) {
152 LOGP(DGGSN, LOGL_ERROR, "Failed to create and send TRAP for IMSI %" PRIu64 " [%s].\n", pdp->imsi, var);
153 return false;
154 }
155 return true;
156}
157
Harald Weltebed35df2011-11-02 13:06:18 +0100158int delete_context(struct pdp_t *pdp)
159{
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100160 DEBUGP(DGGSN, "Deleting PDP context\n");
Max727417d2016-08-02 17:10:38 +0200161 struct ippoolm_t *member = pdp->peer;
Maxdbd70242016-10-14 13:38:05 +0200162
163 if (pdp->peer) {
Max3142d8d2017-05-04 17:45:10 +0200164 send_trap(gsn, pdp, member, "imsi-rem-ip"); /* TRAP with IP removal */
Harald Weltebed35df2011-11-02 13:06:18 +0100165 ippool_freeip(ippool, (struct ippoolm_t *)pdp->peer);
Maxdbd70242016-10-14 13:38:05 +0200166 } else
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100167 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Peer not defined!");
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100168
169 if (gtp_kernel_tunnel_del(pdp)) {
170 SYS_ERR(DGGSN, LOGL_ERROR, 0,
171 "Cannot delete tunnel from kernel: %s\n",
172 strerror(errno));
173 }
174
Harald Weltebed35df2011-11-02 13:06:18 +0100175 return 0;
jjako52c24142002-12-16 13:33:51 +0000176}
177
Harald Weltebed35df2011-11-02 13:06:18 +0100178int create_context_ind(struct pdp_t *pdp)
179{
Harald Welted12eab92017-08-02 19:49:47 +0200180 struct in46_addr addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100181 struct ippoolm_t *member;
Harald Welted1bf1e12017-08-03 00:00:23 +0200182 int rc;
jjako52c24142002-12-16 13:33:51 +0000183
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100184 DEBUGP(DGGSN, "Received create PDP context request\n");
jjako52c24142002-12-16 13:33:51 +0000185
Harald Welted9d88622017-08-04 00:22:35 +0200186 /* FIXME: we manually force all context requests to dynamic here! */
187 if (pdp->eua.l > 2)
188 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +0000189
Harald Weltebed35df2011-11-02 13:06:18 +0100190 memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_req0));
191 memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg));
jjako52c24142002-12-16 13:33:51 +0000192
Harald Weltebed35df2011-11-02 13:06:18 +0100193 memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */
194 pdp->qos_neg.l = pdp->qos_req.l;
jjako52c24142002-12-16 13:33:51 +0000195
Harald Weltea0d281d2017-08-02 21:48:16 +0200196 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Welted1bf1e12017-08-03 00:00:23 +0200197 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Cannot decode EUA from MS/SGSN: %s",
198 osmo_hexdump(pdp->eua.v, pdp->eua.l));
199 gtp_create_context_resp(gsn, pdp, GTPCAUSE_UNKNOWN_PDP);
200 return 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100201 }
jjakoa7cd2492003-04-11 09:40:12 +0000202
Harald Welted1bf1e12017-08-03 00:00:23 +0200203 rc = ippool_newip(ippool, &member, &addr, 0);
204 if (rc < 0) {
205 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Cannot allocate IP address in pool\n");
206 gtp_create_context_resp(gsn, pdp, -rc);
Harald Weltebed35df2011-11-02 13:06:18 +0100207 return 0; /* Allready in use, or no more available */
208 }
jjakoa7cd2492003-04-11 09:40:12 +0000209
Harald Welted46bcd22017-08-08 23:27:22 +0200210 if (addr.len == sizeof(struct in6_addr)) {
211 struct in46_addr tmp;
212 /* IPv6 doesn't really send the real/allocated address at this point, but just
213 * the link-identifier which the MS shall use for router solicitation */
214 tmp.len = addr.len;
215 /* initialize upper 64 bits to prefix, they are discarded by MS anyway */
216 memcpy(tmp.v6.s6_addr, &member->addr.v6, 8);
217 /* use allocated 64bit prefix as lower 64bit, used as link id by MS */
218 memcpy(tmp.v6.s6_addr+8, &member->addr.v6, 8);
219 in46a_to_eua(&tmp, &pdp->eua);
220 } else
221 in46a_to_eua(&member->addr, &pdp->eua);
Harald Weltebed35df2011-11-02 13:06:18 +0100222 pdp->peer = member;
223 pdp->ipif = tun; /* TODO */
224 member->peer = pdp;
jjako52c24142002-12-16 13:33:51 +0000225
Harald Welted46bcd22017-08-08 23:27:22 +0200226 /* TODO: In IPv6, EUA doesn't contain the actual IP addr/prefix! */
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100227 if (gtp_kernel_tunnel_add(pdp) < 0) {
Andreas Schultzc5fbf9b2015-11-17 12:22:43 +0100228 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100229 "Cannot add tunnel to kernel: %s\n", strerror(errno));
Harald Welted1bf1e12017-08-03 00:00:23 +0200230 gtp_create_context_resp(gsn, pdp, GTPCAUSE_SYS_FAIL);
231 return 0;
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100232 }
Max3142d8d2017-05-04 17:45:10 +0200233
234 if (!send_trap(gsn, pdp, member, "imsi-ass-ip")) { /* TRAP with IP assignment */
Max727417d2016-08-02 17:10:38 +0200235 gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES);
236 return 0;
237 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100238
Harald Weltebed35df2011-11-02 13:06:18 +0100239 gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
240 return 0; /* Success */
jjako52c24142002-12-16 13:33:51 +0000241}
242
jjakoa7cd2492003-04-11 09:40:12 +0000243/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +0100244int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
245{
246 struct ippoolm_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +0200247 struct in46_addr dst;
Harald Welte63ebccd2017-08-02 21:10:09 +0200248 struct iphdr *iph = (struct iphdr *)pack;
Harald Weltea0d281d2017-08-02 21:48:16 +0200249 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoc6762cf2004-04-28 14:52:58 +0000250
Harald Welte63ebccd2017-08-02 21:10:09 +0200251 if (iph->version == 4) {
Harald Welted12eab92017-08-02 19:49:47 +0200252 if (len < sizeof(*iph) || len < 4*iph->ihl)
253 return -1;
254 dst.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +0200255 dst.v4.s_addr = iph->daddr;
Harald Weltea0d281d2017-08-02 21:48:16 +0200256 } else if (iph->version == 6) {
Harald Welted4d6e092017-08-08 18:10:43 +0200257 /* Due to the fact that 3GPP requires an allocation of a
258 * /64 prefix to each MS, we must instruct
259 * ippool_getip() below to match only the leading /64
260 * prefix, i.e. the first 8 bytes of the address */
261 dst.len = 8;
Harald Weltea0d281d2017-08-02 21:48:16 +0200262 dst.v6 = ip6h->ip6_dst;
Harald Welted12eab92017-08-02 19:49:47 +0200263 } else {
Harald Weltea0d281d2017-08-02 21:48:16 +0200264 LOGP(DGGSN, LOGL_NOTICE, "non-IPv packet received from tun\n");
Harald Welted12eab92017-08-02 19:49:47 +0200265 return -1;
266 }
jjakoc6762cf2004-04-28 14:52:58 +0000267
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100268 DEBUGP(DGGSN, "Received packet from tun!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100269
270 if (ippool_getip(ippool, &ipm, &dst)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100271 DEBUGP(DGGSN, "Received packet with no destination!!!\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100272 return 0;
273 }
274
275 if (ipm->peer) /* Check if a peer protocol is defined */
276 gtp_data_req(gsn, (struct pdp_t *)ipm->peer, pack, len);
277 return 0;
jjako52c24142002-12-16 13:33:51 +0000278}
279
Harald Welted46bcd22017-08-08 23:27:22 +0200280/* RFC3307 link-local scope multicast address */
281static const struct in6_addr all_router_mcast_addr = {
282 .s6_addr = { 0xff,0x02,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,2 }
283};
284
Harald Weltebed35df2011-11-02 13:06:18 +0100285int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
286{
Harald Welted46bcd22017-08-08 23:27:22 +0200287 struct iphdr *iph = (struct iphdr *)pack;
288 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
289
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100290 DEBUGP(DGGSN, "encaps_tun. Packet received: forwarding to tun\n");
Harald Welted46bcd22017-08-08 23:27:22 +0200291
292 switch (iph->version) {
293 case 6:
294 /* daddr: all-routers multicast addr */
295 if (IN6_ARE_ADDR_EQUAL(&ip6h->ip6_dst, &all_router_mcast_addr))
296 return handle_router_mcast(gsn, pdp, pack, len);
297 break;
298 case 4:
299 break;
300 default:
301 LOGP(DGGSN, LOGL_ERROR, "Packet from MS is neither IPv4 nor IPv6\n");
302 return -1;
303 }
Harald Weltebed35df2011-11-02 13:06:18 +0100304 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +0000305}
306
jjako52c24142002-12-16 13:33:51 +0000307int main(int argc, char **argv)
308{
Harald Weltebed35df2011-11-02 13:06:18 +0100309 /* gengeopt declarations */
310 struct gengetopt_args_info args_info;
jjako52c24142002-12-16 13:33:51 +0000311
Harald Weltebed35df2011-11-02 13:06:18 +0100312 struct hostent *host;
jjako52c24142002-12-16 13:33:51 +0000313
Harald Weltebed35df2011-11-02 13:06:18 +0100314 /* Handle keyboard interrupt SIGINT */
315 struct sigaction s;
316 s.sa_handler = (void *)signal_handler;
317 if ((0 != sigemptyset(&s.sa_mask)) && debug)
318 printf("sigemptyset failed.\n");
319 s.sa_flags = SA_RESETHAND;
320 if ((sigaction(SIGINT, &s, NULL) != 0) && debug)
321 printf("Could not register SIGINT signal handler.\n");
jjako52c24142002-12-16 13:33:51 +0000322
Harald Weltebed35df2011-11-02 13:06:18 +0100323 fd_set fds; /* For select() */
324 struct timeval idleTime; /* How long to select() */
jjako52c24142002-12-16 13:33:51 +0000325
Harald Weltebed35df2011-11-02 13:06:18 +0100326 int timelimit; /* Number of seconds to be connected */
327 int starttime; /* Time program was started */
jjako52c24142002-12-16 13:33:51 +0000328
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100329 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +0000330
Harald Weltebed35df2011-11-02 13:06:18 +0100331 if (cmdline_parser(argc, argv, &args_info) != 0)
332 exit(1);
333 if (args_info.debug_flag) {
334 printf("listen: %s\n", args_info.listen_arg);
335 if (args_info.conf_arg)
336 printf("conf: %s\n", args_info.conf_arg);
337 printf("fg: %d\n", args_info.fg_flag);
338 printf("debug: %d\n", args_info.debug_flag);
339 printf("qos: %#08x\n", args_info.qos_arg);
340 if (args_info.apn_arg)
341 printf("apn: %s\n", args_info.apn_arg);
342 if (args_info.net_arg)
343 printf("net: %s\n", args_info.net_arg);
344 if (args_info.dynip_arg)
345 printf("dynip: %s\n", args_info.dynip_arg);
346 if (args_info.statip_arg)
347 printf("statip: %s\n", args_info.statip_arg);
348 if (args_info.ipup_arg)
349 printf("ipup: %s\n", args_info.ipup_arg);
350 if (args_info.ipdown_arg)
351 printf("ipdown: %s\n", args_info.ipdown_arg);
352 if (args_info.pidfile_arg)
353 printf("pidfile: %s\n", args_info.pidfile_arg);
354 if (args_info.statedir_arg)
355 printf("statedir: %s\n", args_info.statedir_arg);
Pablo Neira Ayusod9d7be32016-05-10 18:43:12 +0200356 if (args_info.gtp_linux_flag)
357 printf("gtp_linux: %d\n", args_info.gtp_linux_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100358 printf("timelimit: %d\n", args_info.timelimit_arg);
359 }
jjako52c24142002-12-16 13:33:51 +0000360
Harald Weltebed35df2011-11-02 13:06:18 +0100361 /* Try out our new parser */
jjako52c24142002-12-16 13:33:51 +0000362
Harald Weltebed35df2011-11-02 13:06:18 +0100363 if (cmdline_parser_configfile(args_info.conf_arg, &args_info, 0, 0, 0)
364 != 0)
365 exit(1);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100366
367 /* Open a log file */
368 if (args_info.logfile_arg) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100369 struct log_target *tgt;
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100370 int lvl;
371
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100372 tgt = log_target_find(LOG_TGT_TYPE_FILE, args_info.logfile_arg);
373 if (!tgt) {
374 tgt = log_target_create_file(args_info.logfile_arg);
375 if (!tgt) {
376 LOGP(DGGSN, LOGL_ERROR,
377 "Failed to create logfile: %s\n",
378 args_info.logfile_arg);
379 exit(1);
380 }
381 log_add_target(tgt);
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100382 }
Holger Hans Peter Freytherc38bf642014-12-04 18:54:58 +0100383 log_set_all_filter(tgt, 1);
384 log_set_use_color(tgt, 0);
385
386 if (args_info.loglevel_arg) {
387 lvl = log_parse_level(args_info.loglevel_arg);
388 log_set_log_level(tgt, lvl);
389 LOGP(DGGSN, LOGL_NOTICE,
390 "Set file log level to %s\n",
391 log_level_str(lvl));
392 }
Holger Hans Peter Freyther9c0ff4f2014-03-23 10:07:26 +0100393 }
394
Harald Weltebed35df2011-11-02 13:06:18 +0100395 if (args_info.debug_flag) {
396 printf("cmdline_parser_configfile\n");
397 printf("listen: %s\n", args_info.listen_arg);
398 printf("conf: %s\n", args_info.conf_arg);
399 printf("fg: %d\n", args_info.fg_flag);
400 printf("debug: %d\n", args_info.debug_flag);
401 printf("qos: %#08x\n", args_info.qos_arg);
402 if (args_info.apn_arg)
403 printf("apn: %s\n", args_info.apn_arg);
404 if (args_info.net_arg)
405 printf("net: %s\n", args_info.net_arg);
406 if (args_info.dynip_arg)
407 printf("dynip: %s\n", args_info.dynip_arg);
408 if (args_info.statip_arg)
409 printf("statip: %s\n", args_info.statip_arg);
410 if (args_info.ipup_arg)
411 printf("ipup: %s\n", args_info.ipup_arg);
412 if (args_info.ipdown_arg)
413 printf("ipdown: %s\n", args_info.ipdown_arg);
414 if (args_info.pidfile_arg)
415 printf("pidfile: %s\n", args_info.pidfile_arg);
416 if (args_info.statedir_arg)
417 printf("statedir: %s\n", args_info.statedir_arg);
Pablo Neira Ayusod9d7be32016-05-10 18:43:12 +0200418 if (args_info.gtp_linux_flag)
419 printf("gtp-linux: %d\n", args_info.gtp_linux_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100420 printf("timelimit: %d\n", args_info.timelimit_arg);
421 }
jjako52c24142002-12-16 13:33:51 +0000422
Harald Weltebed35df2011-11-02 13:06:18 +0100423 /* Handle each option */
jjako52c24142002-12-16 13:33:51 +0000424
Harald Weltebed35df2011-11-02 13:06:18 +0100425 /* debug */
426 debug = args_info.debug_flag;
jjako52c24142002-12-16 13:33:51 +0000427
Harald Weltebed35df2011-11-02 13:06:18 +0100428 /* listen */
429 /* Do hostname lookup to translate hostname to IP address */
430 /* Any port listening is not possible as a valid address is */
431 /* required for create_pdp_context_response messages */
432 if (args_info.listen_arg) {
433 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100434 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100435 "Invalid listening address: %s!",
436 args_info.listen_arg);
437 exit(1);
438 } else {
439 memcpy(&listen_.s_addr, host->h_addr, host->h_length);
440 }
441 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100442 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100443 "Listening address must be specified! "
444 "Please use command line option --listen or "
445 "edit %s configuration file\n", args_info.conf_arg);
446 exit(1);
447 }
jjako88c22162003-07-06 19:33:18 +0000448
Harald Weltebed35df2011-11-02 13:06:18 +0100449 /* net */
450 /* Store net as in_addr net and mask */
451 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200452 struct in46_addr in46;
453 if (ippool_aton(&in46, &prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100454 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100455 "Invalid network address: %s!",
456 args_info.net_arg);
457 exit(1);
458 }
Harald Welted12eab92017-08-02 19:49:47 +0200459 net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100460 netaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
461 destaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
462 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100463 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100464 "Network address must be specified: %s!",
465 args_info.net_arg);
466 exit(1);
467 }
jjako52c24142002-12-16 13:33:51 +0000468
Harald Weltebed35df2011-11-02 13:06:18 +0100469 /* dynip */
470 if (!args_info.dynip_arg) {
471 if (ippool_new(&ippool, args_info.net_arg, NULL, 1, 0,
472 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
473 IPPOOL_NOBROADCAST)) {
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 allocate IP pool!");
476 exit(1);
477 }
478 } else {
479 if (ippool_new(&ippool, args_info.dynip_arg, NULL, 1, 0,
480 IPPOOL_NONETWORK | IPPOOL_NOGATEWAY |
481 IPPOOL_NOBROADCAST)) {
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 allocate IP pool!");
484 exit(1);
485 }
486 }
jjako52c24142002-12-16 13:33:51 +0000487
Harald Weltebed35df2011-11-02 13:06:18 +0100488 /* DNS1 and DNS2 */
jjakoff9985c2004-01-16 11:05:22 +0000489#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +0100490 dns1.s_addr = 0;
491 if (args_info.pcodns1_arg) {
492 if (0 == inet_aton(args_info.pcodns1_arg, &dns1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100493 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100494 "Failed to convert pcodns1!");
495 exit(1);
496 }
497 }
498 dns2.s_addr = 0;
499 if (args_info.pcodns2_arg) {
500 if (0 == inet_aton(args_info.pcodns2_arg, &dns2)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100501 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100502 "Failed to convert pcodns2!");
503 exit(1);
504 }
505 }
jjako1d3db972004-01-16 09:56:56 +0000506#else
Harald Weltebed35df2011-11-02 13:06:18 +0100507 dns1.s_addr = 0;
508 if (args_info.pcodns1_arg) {
509 dns1.s_addr = inet_addr(args_info.pcodns1_arg);
510 if (dns1.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100511 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100512 "Failed to convert pcodns1!");
513 exit(1);
514 }
515 }
516 dns2.s_addr = 0;
517 if (args_info.pcodns2_arg) {
518 dns2.s_addr = inet_addr(args_info.pcodns2_arg);
519 if (dns2.s_addr == -1) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100520 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100521 "Failed to convert pcodns2!");
522 exit(1);
523 }
524 }
jjako1d3db972004-01-16 09:56:56 +0000525#endif
526
Harald Weltebed35df2011-11-02 13:06:18 +0100527 pco.l = 20;
528 pco.v[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
529 pco.v[1] = 0x80; /* IPCP */
530 pco.v[2] = 0x21;
531 pco.v[3] = 0x10; /* Length of contents */
532 pco.v[4] = 0x02; /* ACK */
533 pco.v[5] = 0x00; /* ID: Need to match request */
534 pco.v[6] = 0x00; /* Length */
535 pco.v[7] = 0x10;
536 pco.v[8] = 0x81; /* DNS 1 */
537 pco.v[9] = 0x06;
538 memcpy(&pco.v[10], &dns1, sizeof(dns1));
539 pco.v[14] = 0x83;
540 pco.v[15] = 0x06; /* DNS 2 */
541 memcpy(&pco.v[16], &dns2, sizeof(dns2));
jjakoa7cd2492003-04-11 09:40:12 +0000542
Harald Weltebed35df2011-11-02 13:06:18 +0100543 /* ipup */
544 ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000545
Harald Weltebed35df2011-11-02 13:06:18 +0100546 /* ipdown */
547 ipdown = args_info.ipdown_arg;
jjako4b26b512003-01-28 16:13:57 +0000548
Harald Weltebed35df2011-11-02 13:06:18 +0100549 /* Timelimit */
550 timelimit = args_info.timelimit_arg;
551 starttime = time(NULL);
jjako4b26b512003-01-28 16:13:57 +0000552
Harald Weltebed35df2011-11-02 13:06:18 +0100553 /* qos */
554 qos.l = 3;
555 qos.v[2] = (args_info.qos_arg) & 0xff;
556 qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
557 qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
jjakoa7cd2492003-04-11 09:40:12 +0000558
Harald Weltebed35df2011-11-02 13:06:18 +0100559 /* apn */
560 if (strlen(args_info.apn_arg) > (sizeof(apn.v) - 1)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100561 LOGP(DGGSN, LOGL_ERROR, "Invalid APN\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100562 return -1;
563 }
564 apn.l = strlen(args_info.apn_arg) + 1;
565 apn.v[0] = (char)strlen(args_info.apn_arg);
566 strncpy((char *)&apn.v[1], args_info.apn_arg, sizeof(apn.v) - 1);
jjakoe0149782003-07-06 17:07:04 +0000567
Harald Weltebed35df2011-11-02 13:06:18 +0100568 /* foreground */
569 /* If flag not given run as a daemon */
570 if (!args_info.fg_flag) {
571 FILE *f;
572 int rc;
Harald Weltebed35df2011-11-02 13:06:18 +0100573 /* Close the standard file descriptors. */
574 /* Is this really needed ? */
575 f = freopen("/dev/null", "w", stdout);
576 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100577 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100578 "Could not redirect stdout to /dev/null");
579 }
580 f = freopen("/dev/null", "w", stderr);
581 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100582 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100583 "Could not redirect stderr to /dev/null");
584 }
585 f = freopen("/dev/null", "r", stdin);
586 if (f == NULL) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100587 SYS_ERR(DGGSN, LOGL_NOTICE, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100588 "Could not redirect stdin to /dev/null");
589 }
590 rc = daemon(0, 0);
591 if (rc != 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100592 SYS_ERR(DGGSN, LOGL_ERROR, rc,
Harald Weltebed35df2011-11-02 13:06:18 +0100593 "Could not daemonize");
594 exit(1);
595 }
Harald Weltebed35df2011-11-02 13:06:18 +0100596 }
jjakoe0149782003-07-06 17:07:04 +0000597
Harald Weltebed35df2011-11-02 13:06:18 +0100598 /* pidfile */
599 /* This has to be done after we have our final pid */
600 if (args_info.pidfile_arg) {
601 log_pid(args_info.pidfile_arg);
602 }
jjakoe0149782003-07-06 17:07:04 +0000603
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100604 DEBUGP(DGGSN, "gtpclient: Initialising GTP tunnel\n");
jjako52c24142002-12-16 13:33:51 +0000605
Harald Weltebed35df2011-11-02 13:06:18 +0100606 if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100607 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +0100608 exit(1);
609 }
610 if (gsn->fd0 > maxfd)
611 maxfd = gsn->fd0;
612 if (gsn->fd1c > maxfd)
613 maxfd = gsn->fd1c;
614 if (gsn->fd1u > maxfd)
615 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +0000616
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100617 /* use GTP kernel module for data packet encapsulation */
Harald Welted12eab92017-08-02 19:49:47 +0200618 if (gtp_kernel_init(gsn, &net, prefixlen, &args_info) < 0)
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100619 goto err;
620
Harald Weltebed35df2011-11-02 13:06:18 +0100621 gtp_set_cb_data_ind(gsn, encaps_tun);
622 gtp_set_cb_delete_context(gsn, delete_context);
623 gtp_set_cb_create_context_ind(gsn, create_context_ind);
jjakoa7cd2492003-04-11 09:40:12 +0000624
Max727417d2016-08-02 17:10:38 +0200625 gsn->ctrl = ctrl_interface_setup(NULL, OSMO_CTRL_PORT_GGSN, NULL);
626 if (!gsn->ctrl) {
627 LOGP(DGGSN, LOGL_ERROR, "Failed to create CTRL interface.\n");
628 exit(1);
629 }
630
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100631 /* skip the configuration of the tun0 if we're using the gtp0 device */
632 if (gtp_kernel_enabled())
633 goto skip_tun;
634
Harald Weltebed35df2011-11-02 13:06:18 +0100635 /* Create a tunnel interface */
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100636 DEBUGP(DGGSN, "Creating tun interface\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100637 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100638 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to create tun");
Harald Weltebed35df2011-11-02 13:06:18 +0100639 exit(1);
640 }
jjakoa7cd2492003-04-11 09:40:12 +0000641
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100642 DEBUGP(DGGSN, "Setting tun IP address\n");
Harald Welted12eab92017-08-02 19:49:47 +0200643 if (tun_setaddr(tun, &netaddr, &destaddr, &prefixlen)) {
Holger Hans Peter Freyther6ab58b42014-12-04 19:29:57 +0100644 SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to set tun IP address");
Harald Weltebed35df2011-11-02 13:06:18 +0100645 exit(1);
646 }
jjakoa7cd2492003-04-11 09:40:12 +0000647
Harald Weltebed35df2011-11-02 13:06:18 +0100648 tun_set_cb_ind(tun, cb_tun_ind);
649 if (tun->fd > maxfd)
650 maxfd = tun->fd;
jjakoc6762cf2004-04-28 14:52:58 +0000651
Harald Weltebed35df2011-11-02 13:06:18 +0100652 if (ipup)
653 tun_runscript(tun, ipup);
jjako52c24142002-12-16 13:33:51 +0000654
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100655skip_tun:
656
jjako52c24142002-12-16 13:33:51 +0000657 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +0100658 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +0000659 /******************************************************************/
660
Harald Weltebed35df2011-11-02 13:06:18 +0100661 while ((((starttime + timelimit) > time(NULL)) || (0 == timelimit))
662 && (!end)) {
Harald Weltec3dcba02010-05-04 11:02:54 +0200663
Harald Weltebed35df2011-11-02 13:06:18 +0100664 FD_ZERO(&fds);
665 if (tun)
666 FD_SET(tun->fd, &fds);
667 FD_SET(gsn->fd0, &fds);
668 FD_SET(gsn->fd1c, &fds);
669 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +0000670
Harald Weltebed35df2011-11-02 13:06:18 +0100671 gtp_retranstimeout(gsn, &idleTime);
672 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
673 case -1: /* errno == EINTR : unblocked signal */
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100674 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100675 "select() returned -1");
676 /* On error, select returns without modifying fds */
677 FD_ZERO(&fds);
678 break;
679 case 0:
680 /* printf("Select returned 0\n"); */
681 gtp_retrans(gsn); /* Only retransmit if nothing else */
682 break;
683 default:
684 break;
685 }
jjako52c24142002-12-16 13:33:51 +0000686
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100687 if (tun && tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
Harald Weltebed35df2011-11-02 13:06:18 +0100688 tun_decaps(tun) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100689 SYS_ERR(DGGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100690 "TUN read failed (fd)=(%d)", tun->fd);
691 }
692
693 if (FD_ISSET(gsn->fd0, &fds))
694 gtp_decaps0(gsn);
695
696 if (FD_ISSET(gsn->fd1c, &fds))
697 gtp_decaps1c(gsn);
698
699 if (FD_ISSET(gsn->fd1u, &fds))
700 gtp_decaps1u(gsn);
701
Max727417d2016-08-02 17:10:38 +0200702 osmo_select_main(1);
Harald Weltebed35df2011-11-02 13:06:18 +0100703 }
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100704err:
705 gtp_kernel_stop();
Harald Weltebed35df2011-11-02 13:06:18 +0100706 cmdline_parser_free(&args_info);
707 ippool_free(ippool);
708 gtp_free(gsn);
Pablo Neira Ayuso4b075b62015-11-17 12:22:42 +0100709 if (tun)
710 tun_free(tun);
Harald Weltebed35df2011-11-02 13:06:18 +0100711
712 return 1;
713
jjako52c24142002-12-16 13:33:51 +0000714}