blob: 36b52fcf1a4172d01dad9fbf77f42aaaed1d50d3 [file] [log] [blame]
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01001/*
Harald Welte632e8432017-09-05 18:12:14 +02002 * OsmoGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
Harald Welte6748dc92017-09-24 21:54:59 +08004 * Copyright (C) 2017 Harald Welte <laforge@gnumonks.org>
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01005 *
jjako52c24142002-12-16 13:33:51 +00006 * The contents of this file may be used under the terms of the GNU
7 * General Public License Version 2, provided that the above copyright
8 * notice and this permission notice is included in all copies or
9 * substantial portions of the software.
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +010010 *
jjako52c24142002-12-16 13:33:51 +000011 */
12
13/*
14 * sgsnemu.c
15 *
16 */
17
jjako52c24142002-12-16 13:33:51 +000018#ifdef __linux__
Harald Weltebed35df2011-11-02 13:06:18 +010019#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000020#endif
21
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010022#include <osmocom/core/application.h>
Pau Espin Pedrol042a4452018-04-17 14:31:42 +020023#include <osmocom/core/msgb.h>
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010024
jjako52c24142002-12-16 13:33:51 +000025#include <ctype.h>
26#include <netdb.h>
27#include <signal.h>
28#include <stdio.h>
29#include <string.h>
30#include <stdlib.h>
31#include <sys/types.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020034#include <netinet/ip.h>
Harald Welte6748dc92017-09-24 21:54:59 +080035#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000036#include <arpa/inet.h>
37#include <sys/wait.h>
38#include <sys/stat.h>
39#include <unistd.h>
40#include <sys/socket.h>
41#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000042#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000043#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000044#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000045#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000046#include <resolv.h>
47#include <time.h>
48
jjakoff9985c2004-01-16 11:05:22 +000049#include "config.h"
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020050#include "../lib/tun.h"
51#include "../lib/ippool.h"
52#include "../lib/syserr.h"
jjako52c24142002-12-16 13:33:51 +000053#include "../gtp/pdp.h"
54#include "../gtp/gtp.h"
55#include "cmdline.h"
56
Harald Weltebed35df2011-11-02 13:06:18 +010057#define IPADDRLEN 256 /* Character length of addresses */
58#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000059
jjakoa7cd2492003-04-11 09:40:12 +000060/* HASH tables for IP address allocation */
61struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010062 uint8_t inuse; /* 0=free. 1=used by somebody */
63 struct iphash_t *ipnext;
64 struct pdp_t *pdp;
Harald Welted12eab92017-08-02 19:49:47 +020065 struct in46_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000066};
67struct iphash_t iparr[MAXCONTEXTS];
68struct iphash_t *iphash[MAXCONTEXTS];
69
70/* State variable used for ping */
71/* 0: Idle */
72/* 1: Wait_connect */
73/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000074/* 3: Done */
75/* 4: Wait_disconnect */
76/* 5: Disconnected */
bjovana8f71eb2017-02-24 17:39:20 +010077volatile sig_atomic_t state = 0;
jjako52c24142002-12-16 13:33:51 +000078
Harald Weltebed35df2011-11-02 13:06:18 +010079struct gsn_t *gsn = NULL; /* GSN instance */
80struct tun_t *tun = NULL; /* TUN instance */
81int maxfd = 0; /* For select() */
82int echoversion = 1; /* First try this version */
Pau Espin Pedrol042a4452018-04-17 14:31:42 +020083void *tall_sgsnemu_ctx; /* root talloc ctx */
jjako52c24142002-12-16 13:33:51 +000084
jjakoa7cd2492003-04-11 09:40:12 +000085/* Struct with local versions of gengetopt options */
86struct {
Harald Weltebed35df2011-11-02 13:06:18 +010087 int debug; /* Print debug messages */
88 int createif; /* Create local network interface */
Harald Welte73abc382017-10-10 08:50:11 +080089 char *tun_dev_name;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +010090 struct in46_addr netaddr, destaddr, net; /* Network interface */
Harald Welted12eab92017-08-02 19:49:47 +020091 size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +010092 char *ipup, *ipdown; /* Filename of scripts */
93 int defaultroute; /* Set up default route */
94 struct in_addr pinghost; /* Remote ping host */
95 int pingrate;
96 int pingsize;
97 int pingcount;
98 int pingquiet;
99 struct in_addr listen;
100 struct in_addr remote;
101 struct in_addr dns;
102 int contexts; /* Number of contexts to create */
103 int timelimit; /* Number of seconds to be connected */
104 char *statedir;
105 uint64_t imsi;
106 uint8_t nsapi;
107 int gtpversion;
108 struct ul255_t pco;
109 struct ul255_t qos;
110 uint16_t cch;
111 struct ul255_t apn;
112 uint8_t selmode;
113 struct ul255_t rattype;
114 int rattype_given;
115 struct ul255_t userloc;
116 int userloc_given;
117 struct ul255_t rai;
118 int rai_given;
119 struct ul255_t mstz;
120 int mstz_given;
121 struct ul255_t imeisv;
122 int imeisv_given;
123 struct ul16_t msisdn;
124 int norecovery_given;
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800125 int tx_gpdu_seq;
Harald Welte840a8e92017-09-24 18:12:40 +0800126 uint8_t pdp_type;
jjakoa7cd2492003-04-11 09:40:12 +0000127} options;
jjako52c24142002-12-16 13:33:51 +0000128
jjako5da68452003-01-28 16:08:47 +0000129/* Definitions to use for PING. Most of the ping code was derived from */
130/* the original ping program by Mike Muuss */
131
132/* IP header and ICMP echo header */
133#define CREATEPING_MAX 2048
134#define CREATEPING_IP 20
135#define CREATEPING_ICMP 8
136
137struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100138 uint8_t ipver; /* Type and header length */
139 uint8_t tos; /* Type of Service */
140 uint16_t length; /* Total length */
141 uint16_t fragid; /* Identifier */
142 uint16_t offset; /* Flags and fragment offset */
143 uint8_t ttl; /* Time to live */
144 uint8_t protocol; /* Protocol */
145 uint16_t ipcheck; /* Header checksum */
146 uint32_t src; /* Source address */
147 uint32_t dst; /* Destination */
148 uint8_t type; /* Type and header length */
149 uint8_t code; /* Code */
150 uint16_t checksum; /* Header checksum */
151 uint16_t ident; /* Identifier */
152 uint16_t seq; /* Sequence number */
153 uint8_t data[CREATEPING_MAX]; /* Data */
154} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000155
156/* Statistical values for ping */
157int nreceived = 0;
158int ntreceived = 0;
159int ntransmitted = 0;
160int tmin = 999999999;
161int tmax = 0;
162int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100163int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000164struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000165
Harald Weltefed33892017-10-10 09:02:45 +0800166static void signal_handler(int signo)
bjovana8f71eb2017-02-24 17:39:20 +0100167{
168 if (state == 2)
169 state = 3; /* Tell main loop to finish. */
170}
171
Harald Weltefed33892017-10-10 09:02:45 +0800172static int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100173{
Harald Welted12eab92017-08-02 19:49:47 +0200174 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100175 struct iphash_t *h;
176 struct iphash_t *prev = NULL;
177 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200178 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100179 for (h = iphash[hash]; h; h = h->ipnext)
180 prev = h;
181 if (!prev)
182 iphash[hash] = ipaddr;
183 else
184 prev->ipnext = ipaddr;
185 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000186}
187
Harald Weltefed33892017-10-10 09:02:45 +0800188static int ipdel(struct iphash_t *ipaddr)
Harald Weltebed35df2011-11-02 13:06:18 +0100189{
Harald Welted12eab92017-08-02 19:49:47 +0200190 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100191 struct iphash_t *h;
192 struct iphash_t *prev = NULL;
193 for (h = iphash[hash]; h; h = h->ipnext) {
194 if (h == ipaddr) {
195 if (!prev)
196 iphash[hash] = h->ipnext;
197 else
198 prev->ipnext = h->ipnext;
199 return 0;
200 }
201 prev = h;
202 }
203 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000204}
205
Harald Weltefed33892017-10-10 09:02:45 +0800206static int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100207{
Harald Welted12eab92017-08-02 19:49:47 +0200208 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100209 struct iphash_t *h;
210 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200211 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100212 *ipaddr = h;
213 return 0;
214 }
215 }
216 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000217}
218
jjakoa7cd2492003-04-11 09:40:12 +0000219/* Used to write process ID to file. Assume someone else will delete */
Harald Weltefed33892017-10-10 09:02:45 +0800220static void log_pid(char *pidfile)
Harald Weltebed35df2011-11-02 13:06:18 +0100221{
222 FILE *file;
223 mode_t oldmask;
224
225 oldmask = umask(022);
226 file = fopen(pidfile, "w");
227 umask(oldmask);
228 if (!file)
229 return;
230 fprintf(file, "%d\n", (int)getpid());
231 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000232}
233
Harald Weltefed33892017-10-10 09:02:45 +0800234static int process_options(int argc, char **argv)
Harald Weltebed35df2011-11-02 13:06:18 +0100235{
236 /* gengeopt declarations */
237 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000238
Harald Weltebed35df2011-11-02 13:06:18 +0100239 struct hostent *host;
240 unsigned int n;
241 uint16_t i;
242 uint8_t a;
243 uint8_t b;
244 char *tmp;
245 char *pch;
246 char *type;
247 char *mcc;
248 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100249 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100250 char *lac;
251 int lac_d;
252 char *rest;
253 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
254 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
255 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
256 int sign;
257 int nbquarters;
258 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000259
Harald Weltebed35df2011-11-02 13:06:18 +0100260 if (cmdline_parser(argc, argv, &args_info) != 0)
261 return -1;
262 if (args_info.debug_flag) {
263 if (args_info.remote_arg)
264 printf("remote: %s\n", args_info.remote_arg);
265 if (args_info.listen_arg)
266 printf("listen: %s\n", args_info.listen_arg);
267 if (args_info.conf_arg)
268 printf("conf: %s\n", args_info.conf_arg);
269 printf("debug: %d\n", args_info.debug_flag);
270 if (args_info.imsi_arg)
271 printf("imsi: %s\n", args_info.imsi_arg);
272 printf("qos: %#08x\n", args_info.qos_arg);
273 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
274 printf("qose2: %#04x\n", args_info.qose2_arg);
275 printf("qose3: %#06x\n", args_info.qose3_arg);
276 printf("qose4: %#06x\n", args_info.qose4_arg);
277 printf("charging: %#04x\n", args_info.charging_arg);
278 if (args_info.apn_arg)
279 printf("apn: %s\n", args_info.apn_arg);
280 if (args_info.msisdn_arg)
281 printf("msisdn: %s\n", args_info.msisdn_arg);
282 if (args_info.uid_arg)
283 printf("uid: %s\n", args_info.uid_arg);
284 if (args_info.pwd_arg)
285 printf("pwd: %s\n", args_info.pwd_arg);
286 if (args_info.pidfile_arg)
287 printf("pidfile: %s\n", args_info.pidfile_arg);
288 if (args_info.statedir_arg)
289 printf("statedir: %s\n", args_info.statedir_arg);
290 if (args_info.dns_arg)
291 printf("dns: %s\n", args_info.dns_arg);
292 printf("contexts: %d\n", args_info.contexts_arg);
293 printf("timelimit: %d\n", args_info.timelimit_arg);
294 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800295 if (args_info.tun_device_arg)
Harald Welte7b9230a2018-10-21 13:09:21 +0200296 printf("tun-device: %s\n", args_info.tun_device_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100297 if (args_info.ipup_arg)
298 printf("ipup: %s\n", args_info.ipup_arg);
299 if (args_info.ipdown_arg)
300 printf("ipdown: %s\n", args_info.ipdown_arg);
301 printf("defaultroute: %d\n", args_info.defaultroute_flag);
302 if (args_info.pinghost_arg)
303 printf("pinghost: %s\n", args_info.pinghost_arg);
304 printf("pingrate: %d\n", args_info.pingrate_arg);
305 printf("pingsize: %d\n", args_info.pingsize_arg);
306 printf("pingcount: %d\n", args_info.pingcount_arg);
307 printf("pingquiet: %d\n", args_info.pingquiet_flag);
308 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800309 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100310 }
jjakoa7cd2492003-04-11 09:40:12 +0000311
Harald Weltebed35df2011-11-02 13:06:18 +0100312 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000313
Harald Weltebed35df2011-11-02 13:06:18 +0100314 if (args_info.conf_arg) {
315 if (cmdline_parser_configfile
316 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
317 return -1;
318 if (args_info.debug_flag) {
319 printf("cmdline_parser_configfile\n");
320 if (args_info.remote_arg)
321 printf("remote: %s\n", args_info.remote_arg);
322 if (args_info.listen_arg)
323 printf("listen: %s\n", args_info.listen_arg);
324 if (args_info.conf_arg)
325 printf("conf: %s\n", args_info.conf_arg);
326 printf("debug: %d\n", args_info.debug_flag);
327 if (args_info.imsi_arg)
328 printf("imsi: %s\n", args_info.imsi_arg);
329 printf("qos: %#08x\n", args_info.qos_arg);
330 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
331 printf("qose2: %#04x\n", args_info.qose2_arg);
332 printf("qose3: %#06x\n", args_info.qose3_arg);
333 printf("qose4: %#06x\n", args_info.qose4_arg);
334 printf("charging: %#04x\n", args_info.charging_arg);
335 if (args_info.apn_arg)
336 printf("apn: %s\n", args_info.apn_arg);
337 if (args_info.msisdn_arg)
338 printf("msisdn: %s\n", args_info.msisdn_arg);
339 if (args_info.uid_arg)
340 printf("uid: %s\n", args_info.uid_arg);
341 if (args_info.pwd_arg)
342 printf("pwd: %s\n", args_info.pwd_arg);
343 if (args_info.pidfile_arg)
344 printf("pidfile: %s\n", args_info.pidfile_arg);
345 if (args_info.statedir_arg)
346 printf("statedir: %s\n",
347 args_info.statedir_arg);
348 if (args_info.dns_arg)
349 printf("dns: %s\n", args_info.dns_arg);
350 printf("contexts: %d\n", args_info.contexts_arg);
351 printf("timelimit: %d\n", args_info.timelimit_arg);
352 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800353 if (args_info.tun_device_arg)
Harald Welte9c332102017-11-06 02:44:42 +0900354 printf("tun-device: %s\n", args_info.tun_device_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100355 if (args_info.ipup_arg)
356 printf("ipup: %s\n", args_info.ipup_arg);
357 if (args_info.ipdown_arg)
358 printf("ipdown: %s\n", args_info.ipdown_arg);
359 printf("defaultroute: %d\n",
360 args_info.defaultroute_flag);
361 if (args_info.pinghost_arg)
362 printf("pinghost: %s\n",
363 args_info.pinghost_arg);
364 printf("pingrate: %d\n", args_info.pingrate_arg);
365 printf("pingsize: %d\n", args_info.pingsize_arg);
366 printf("pingcount: %d\n", args_info.pingcount_arg);
367 printf("pingquiet: %d\n", args_info.pingquiet_flag);
368 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800369 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100370 }
371 }
jjako193e8b12003-11-10 12:31:41 +0000372
Harald Weltebed35df2011-11-02 13:06:18 +0100373 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000374
Harald Weltebed35df2011-11-02 13:06:18 +0100375 /* foreground */
376 /* If fg flag not given run as a daemon */
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100377 /* Do not allow sgsnemu to run as deamon
Harald Weltebed35df2011-11-02 13:06:18 +0100378 if (!args_info.fg_flag)
379 {
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100380 closelog();
Harald Weltebed35df2011-11-02 13:06:18 +0100381 freopen("/dev/null", "w", stdout);
382 freopen("/dev/null", "w", stderr);
383 freopen("/dev/null", "r", stdin);
384 daemon(0, 0);
385 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
386 } */
jjako1a51df72004-07-20 08:30:21 +0000387
Harald Weltebed35df2011-11-02 13:06:18 +0100388 /* debug */
389 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000390
Harald Weltebed35df2011-11-02 13:06:18 +0100391 /* pidfile */
392 /* This has to be done after we have our final pid */
393 if (args_info.pidfile_arg) {
394 log_pid(args_info.pidfile_arg);
395 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200396
Harald Weltebed35df2011-11-02 13:06:18 +0100397 /* dns */
398 /* If no dns option is given use system default */
399 /* Do hostname lookup to translate hostname to IP address */
400 printf("\n");
401 if (args_info.dns_arg) {
402 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100403 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100404 "Invalid DNS address: %s!", args_info.dns_arg);
405 return -1;
406 } else {
407 memcpy(&options.dns.s_addr, host->h_addr,
408 host->h_length);
409 _res.nscount = 1;
410 _res.nsaddr_list[0].sin_addr = options.dns;
411 printf("Using DNS server: %s (%s)\n",
412 args_info.dns_arg, inet_ntoa(options.dns));
413 }
414 } else {
415 options.dns.s_addr = 0;
416 printf("Using default DNS server\n");
417 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200418
Harald Weltebed35df2011-11-02 13:06:18 +0100419 /* listen */
420 /* If no listen option is specified listen to any local port */
421 /* Do hostname lookup to translate hostname to IP address */
422 if (args_info.listen_arg) {
423 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100424 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100425 "Invalid listening address: %s!",
426 args_info.listen_arg);
427 return -1;
428 } else {
429 memcpy(&options.listen.s_addr, host->h_addr,
430 host->h_length);
431 printf("Local IP address is: %s (%s)\n",
432 args_info.listen_arg, inet_ntoa(options.listen));
433 }
434 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100435 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100436 "Listening address must be specified: %s!",
437 args_info.listen_arg);
438 return -1;
439 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200440
Harald Weltebed35df2011-11-02 13:06:18 +0100441 /* remote */
442 /* If no remote option is specified terminate */
443 /* Do hostname lookup to translate hostname to IP address */
444 if (args_info.remote_arg) {
445 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100446 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100447 "Invalid remote address: %s!",
448 args_info.remote_arg);
449 return -1;
450 } else {
451 memcpy(&options.remote.s_addr, host->h_addr,
452 host->h_length);
453 printf("Remote IP address is: %s (%s)\n",
454 args_info.remote_arg, inet_ntoa(options.remote));
455 }
456 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100457 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100458 "No remote address given!");
459 return -1;
460 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200461
Harald Weltebed35df2011-11-02 13:06:18 +0100462 /* imsi */
463 if (strlen(args_info.imsi_arg) != 15) {
464 printf("Invalid IMSI\n");
465 return -1;
466 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200467
Harald Weltebed35df2011-11-02 13:06:18 +0100468 options.imsi = 0xf000000000000000ull;
469 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
470 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
471 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
472 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
473 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
474 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
475 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
476 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
477 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
478 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
479 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
480 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
481 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
482 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
483 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200484
Harald Weltebed35df2011-11-02 13:06:18 +0100485 printf("IMSI is: %s (%#08llx)\n",
486 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200487
Harald Weltebed35df2011-11-02 13:06:18 +0100488 /* nsapi */
489 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
490 printf("Invalid NSAPI\n");
491 return -1;
492 }
493 options.nsapi = args_info.nsapi_arg;
494 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200495
Harald Weltebed35df2011-11-02 13:06:18 +0100496 /* qos */
497 options.qos.l = 4;
498 options.qos.v[3] = (args_info.qos_arg) & 0xff;
499 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
500 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
501 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
502 /* Extensions according to 3GPP TS 24.008 */
503 if (args_info.qose1_given == 1) {
504 options.qos.l = 12;
505 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
506 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
507 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
508 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
509 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
510 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
511 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
512 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
513 if (args_info.qose2_given == 1) {
514 options.qos.l = 13;
515 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
516 if (args_info.qose3_given == 1) {
517 options.qos.l = 15;
518 options.qos.v[14] =
519 (args_info.qose3_arg) & 0xff;
520 options.qos.v[13] =
521 ((args_info.qose3_arg) >> 8) & 0xff;
522 if (args_info.qose4_given == 1) {
523 options.qos.l = 17;
524 options.qos.v[16] =
525 (args_info.qose4_arg) & 0xff;
526 options.qos.v[15] =
527 ((args_info.qose4_arg) >> 8) & 0xff;
528 }
529 }
530 }
531 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200532
Harald Weltebed35df2011-11-02 13:06:18 +0100533 /* charging */
534 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200535
Harald Weltebed35df2011-11-02 13:06:18 +0100536 /* contexts */
537 if (args_info.contexts_arg > MAXCONTEXTS) {
538 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
539 return -1;
540 }
541 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200542
Harald Weltebed35df2011-11-02 13:06:18 +0100543 /* Timelimit */
544 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200545
Harald Weltebed35df2011-11-02 13:06:18 +0100546 /* gtpversion */
547 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
548 printf("Invalid GTP version\n");
549 return -1;
550 }
551 options.gtpversion = args_info.gtpversion_arg;
552 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200553
Harald Weltebed35df2011-11-02 13:06:18 +0100554 /* apn */
555 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
556 printf("Invalid APN\n");
557 return -1;
558 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100559 options.apn.l = strlen(args_info.apn_arg) + 1;
560
561 apn = (char *)options.apn.v;
562 for (tok = strtok(args_info.apn_arg, ".");
563 tok != NULL;
564 tok = strtok(NULL, ".")) {
565 size_t len = strlen(tok);
566
567 *apn++ = (char)len;
568 strncpy(apn, tok, len);
569 apn += len;
570 }
571
Harald Weltebed35df2011-11-02 13:06:18 +0100572 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200573
Harald Weltebed35df2011-11-02 13:06:18 +0100574 /* selmode */
575 options.selmode = args_info.selmode_arg;
576 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200577
Harald Weltebed35df2011-11-02 13:06:18 +0100578 /* rattype */
579 if (args_info.rattype_given == 1) {
580 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800581 options.rattype.l = 1;
582 options.rattype.v[0] = args_info.rattype_arg;
583 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100584 }
Harald Welte41af5692011-10-07 18:42:34 +0200585
Harald Weltebed35df2011-11-02 13:06:18 +0100586 /* userloc */
587 if (args_info.userloc_given == 1) {
588 printf("Using User Location Information: %s\n",
589 args_info.userloc_arg);
590 tmp = args_info.userloc_arg;
591 n = 0;
592 pch = strtok(tmp, ".");
593 while (pch != NULL) {
594 userloc_el[n] = pch;
595 pch = strtok(NULL, ".");
596 n++;
597 }
Harald Welte41af5692011-10-07 18:42:34 +0200598
Harald Weltebed35df2011-11-02 13:06:18 +0100599 options.userloc_given = 1;
600 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200601
Harald Weltebed35df2011-11-02 13:06:18 +0100602 /* 3GPP Geographic Location Type t0 / t1 / t2 */
603 type = userloc_el[0];
604 printf("->type : %c\n", type[0]);
605 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
606 printf("Invalid type \n");
607 return -1;
608 }
609 /* options.userloc.v[0] = 0x00 */
610 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200611
Harald Weltebed35df2011-11-02 13:06:18 +0100612 /* MCC */
613 mcc = userloc_el[1];
614 printf("->mcc : %s\n", mcc);
615 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200616 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100617 return -1;
618 }
Harald Welte41af5692011-10-07 18:42:34 +0200619
Harald Weltebed35df2011-11-02 13:06:18 +0100620 /* MNC */
621 mnc = userloc_el[2];
622 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200623
Harald Weltebed35df2011-11-02 13:06:18 +0100624 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
625 /* options.userloc.v[1] = 0x52 */
626 a = (uint8_t) (mcc[0] - 48);
627 b = (uint8_t) (mcc[1] - 48);
628 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200629
Harald Weltebed35df2011-11-02 13:06:18 +0100630 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
631 /* options.userloc.v[2] = 0xf0 */
632 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200633
Harald Weltebed35df2011-11-02 13:06:18 +0100634 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200635 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100636 return -1;
637 }
638 if (strlen(mnc) == 2) {
639 b = 15;
640 }
641 if (strlen(mnc) == 3) {
642 b = (uint8_t) (mnc[2] - 48);
643 }
644 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200645
Harald Weltebed35df2011-11-02 13:06:18 +0100646 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
647 /* options.userloc.v[3] = 0x99 */
648 a = (uint8_t) (mnc[0] - 48);
649 b = (uint8_t) (mnc[1] - 48);
650 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200651
Harald Weltebed35df2011-11-02 13:06:18 +0100652 /* LAC */
653 lac = userloc_el[3];
654 /*options.userloc.v[4] = 0x12 ; */
655 /*options.userloc.v[5] = 0x10 ; */
656 printf("->LAC: %s\n", lac);
657 lac_d = atoi(lac);
658 if (lac_d > 65535 || lac_d < 1) {
659 printf("Invalid LAC\n");
660 return -1;
661 }
662 i = lac_d >> 8;
663 options.userloc.v[4] = i; /* octet 8 - LAC */
664 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200665
Harald Weltebed35df2011-11-02 13:06:18 +0100666 /* CI/SAC/RAC */
667 rest = userloc_el[4];
668 printf("->CI/SAC/RAC : %s\n", rest);
669 lac_d = atoi(rest);
670 if (lac_d > 65535 || lac_d < 1) {
671 printf("Invalid CI/SAC/RAC\n");
672 return -1;
673 }
674 /*options.userloc.v[6] = 0x04 ; */
675 /*options.userloc.v[7] = 0xb7 ; */
676 i = lac_d >> 8;
677 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
678 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
679 }
jjakoa7cd2492003-04-11 09:40:12 +0000680
Harald Weltebed35df2011-11-02 13:06:18 +0100681 /* RAI */
682 if (args_info.rai_given == 1) {
683 printf("Using RAI: %s\n", args_info.rai_arg);
684 tmp = args_info.rai_arg;
685 n = 0;
686 pch = strtok(tmp, ".");
687 while (pch != NULL) {
688 rai_el[n] = pch;
689 pch = strtok(NULL, ".");
690 n++;
691 }
jjakoa7cd2492003-04-11 09:40:12 +0000692
Harald Weltebed35df2011-11-02 13:06:18 +0100693 options.rai_given = 1;
694 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000695
Harald Weltebed35df2011-11-02 13:06:18 +0100696 /* MCC */
697 mcc = rai_el[0];
698 printf("->mcc : %s\n", mcc);
699 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200700 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100701 return -1;
702 }
703
704 /* MNC */
705 mnc = rai_el[1];
706 printf("->mnc : %s\n", mnc);
707
708 a = (uint8_t) (mcc[0] - 48);
709 b = (uint8_t) (mcc[1] - 48);
710 options.rai.v[0] = 16 * b + a;
711
712 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
713 a = (uint8_t) (mcc[2] - 48);
714
715 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200716 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100717 return -1;
718 }
719 if (strlen(mnc) == 2) {
720 b = 15;
721 }
722 if (strlen(mnc) == 3) {
723 b = (uint8_t) (mnc[2] - 48);
724 }
725 options.rai.v[1] = 16 * b + a;
726
727 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
728 a = (uint8_t) (mnc[0] - 48);
729 b = (uint8_t) (mnc[1] - 48);
730 options.rai.v[2] = 16 * b + a;
731
732 /* LAC */
733 lac = rai_el[2];
734 printf("->LAC: %s\n", lac);
735 lac_d = atoi(lac);
736 if (lac_d > 65535 || lac_d < 1) {
737 printf("Invalid LAC\n");
738 return -1;
739 }
740 i = lac_d >> 8;
741 options.rai.v[3] = i; /* octet 5 - LAC */
742 options.rai.v[4] = lac_d; /* octet 6 - LAC */
743
744 /* RAC */
745 rest = rai_el[3];
746 printf("->RAC : %s\n", rest);
747 lac_d = atoi(rest);
748 if (lac_d > 255 || lac_d < 1) {
749 printf("Invalid RAC\n");
750 return -1;
751 }
752 options.rai.v[5] = lac_d; /* octet 7 - RAC */
753 }
754
755 /* mstz */
756 if (args_info.mstz_given == 1) {
757 options.mstz_given = 1;
758 options.mstz.l = 2;
759
760 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
761 tmp = args_info.mstz_arg;
762 n = 0;
763 pch = strtok(tmp, ".");
764 while (pch != NULL) {
765 mstz_el[n] = pch;
766 pch = strtok(NULL, ".");
767 n++;
768 }
769
770 /* sign */
771 sign = atoi(mstz_el[0]);
772 printf("->Sign (0=+ / 1=-): %d\n", sign);
773 if (sign != 0 && sign != 1) {
774 printf("Invalid Sign \n");
775 return -1;
776 }
777 /* nbquarters */
778 nbquarters = atoi(mstz_el[1]);
779 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
780 if (nbquarters < 0 || nbquarters > 79) {
781 printf("Invalid Number of Quarters \n");
782 return -1;
783 }
784 /* DST */
785 DST = atoi(mstz_el[2]);
786 printf("->Daylight Saving Time Adjustment : %d\n", DST);
787 if (DST < 0 || DST > 3) {
788 printf("Invalid DST Adjustment \n");
789 return -1;
790 }
791 /* 12345678
792 bits 123 = unit of # of quarters of an hour
793 bits 678 = # of quarters of an hour / 10
794 bit 5 = sign
795 */
796 i = nbquarters % 10;
797 i = i << 4;
798 i = i + nbquarters / 10 + 8 * sign;
799 /* options.mstz.v[0] = 0x69 ; */
800 /* options.mstz.v[1] = 0x01 ; */
801 options.mstz.v[0] = i;
802 options.mstz.v[1] = DST;
803 n = (i & 0x08) ? '-' : '+';
804 printf
805 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
806 n, nbquarters / 4, nbquarters % 4 * 15);
807 }
808
809 /* imeisv */
810 if (args_info.imeisv_given == 1) {
811 options.imeisv_given = 1;
812 if (strlen(args_info.imeisv_arg) != 16) {
813 printf("Invalid IMEI(SV)\n");
814 return -1;
815 }
816 options.imeisv.l = 8;
817 for (n = 0; n < 8; n++) {
818 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
819 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
820 options.imeisv.v[n] = 16 * b + a;
821 }
822 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
823 }
824
825 /* msisdn */
826 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
827 printf("Invalid MSISDN\n");
828 return -1;
829 }
830 options.msisdn.l = 1;
831 options.msisdn.v[0] = 0x91; /* International format */
832 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
833 if ((n % 2) == 0) {
834 options.msisdn.v[((int)n / 2) + 1] =
835 args_info.msisdn_arg[n] - 48 + 0xf0;
836 options.msisdn.l += 1;
837 } else {
838 options.msisdn.v[((int)n / 2) + 1] =
839 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
840 (args_info.msisdn_arg[n] - 48) * 16;
841 }
842 }
843 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
844
845 /* UID and PWD */
846 /* Might need to also insert stuff like DNS etc. */
847 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
848 (sizeof(options.pco.v) - 1)) {
849 printf("invalid UID and PWD\n");
850 return -1;
851 }
852 options.pco.l =
853 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
854 options.pco.v[0] = 0x80; /* PPP */
855 options.pco.v[1] = 0xc0; /* PAP */
856 options.pco.v[2] = 0x23;
857 options.pco.v[3] =
858 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
859 options.pco.v[4] = 0x01; /* Authenticate request */
860 options.pco.v[5] = 0x01;
861 options.pco.v[6] = 0x00; /* MSB of length */
862 options.pco.v[7] =
863 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
864 options.pco.v[8] = strlen(args_info.uid_arg);
865 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
866 options.pco.v[9 + strlen(args_info.uid_arg)] =
867 strlen(args_info.pwd_arg);
868 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
869 args_info.pwd_arg, strlen(args_info.pwd_arg));
870
871 /* createif */
872 options.createif = args_info.createif_flag;
Harald Welte73abc382017-10-10 08:50:11 +0800873 options.tun_dev_name = args_info.tun_device_arg;
Harald Weltebed35df2011-11-02 13:06:18 +0100874
875 /* net */
876 /* Store net as in_addr net and mask */
877 if (args_info.net_arg) {
878 if (ippool_aton
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100879 (&options.net, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100880 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100881 "Invalid network address: %s!",
882 args_info.net_arg);
883 exit(1);
884 }
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100885 options.netaddr = options.net;
886 options.destaddr = options.net;
jjakoc6762cf2004-04-28 14:52:58 +0000887
Harald Weltebed35df2011-11-02 13:06:18 +0100888 } else {
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100889 memset(&options.net, 0, sizeof(options.net));
Harald Welted12eab92017-08-02 19:49:47 +0200890 options.prefixlen = 0;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100891 memset(&options.netaddr, 0, sizeof(options.netaddr));
892 memset(&options.destaddr, 0, sizeof(options.destaddr));
Harald Weltebed35df2011-11-02 13:06:18 +0100893 }
jjako193e8b12003-11-10 12:31:41 +0000894
Harald Weltebed35df2011-11-02 13:06:18 +0100895 /* ipup */
896 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000897
Harald Weltebed35df2011-11-02 13:06:18 +0100898 /* ipdown */
899 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000900
Harald Weltebed35df2011-11-02 13:06:18 +0100901 /* statedir */
902 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000903
Harald Weltebed35df2011-11-02 13:06:18 +0100904 /* defaultroute */
905 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000906
Harald Weltebed35df2011-11-02 13:06:18 +0100907 /* pinghost */
908 /* Store ping host as in_addr */
909 if (args_info.pinghost_arg) {
910 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100911 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100912 "Invalid ping host: %s!",
913 args_info.pinghost_arg);
914 return -1;
915 } else {
916 memcpy(&options.pinghost.s_addr, host->h_addr,
917 host->h_length);
918 printf("Using ping host: %s (%s)\n",
919 args_info.pinghost_arg,
920 inet_ntoa(options.pinghost));
921 }
922 }
jjakoa7cd2492003-04-11 09:40:12 +0000923
Harald Weltebed35df2011-11-02 13:06:18 +0100924 /* Other ping parameters */
925 options.pingrate = args_info.pingrate_arg;
926 options.pingsize = args_info.pingsize_arg;
927 options.pingcount = args_info.pingcount_arg;
928 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000929
Harald Weltebed35df2011-11-02 13:06:18 +0100930 /* norecovery */
931 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000932
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800933 if (args_info.no_tx_gpdu_seq_flag)
934 options.tx_gpdu_seq = 0;
935 else
936 options.tx_gpdu_seq = 1;
937
Harald Welte840a8e92017-09-24 18:12:40 +0800938 /* PDP Type */
939 if (!strcmp(args_info.pdp_type_arg, "v6"))
940 options.pdp_type = PDP_EUA_TYPE_v6;
Harald Welte6748dc92017-09-24 21:54:59 +0800941 else if (!strcmp(args_info.pdp_type_arg, "v4"))
Harald Welte840a8e92017-09-24 18:12:40 +0800942 options.pdp_type = PDP_EUA_TYPE_v4;
Harald Welte6748dc92017-09-24 21:54:59 +0800943 else {
944 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
945 args_info.pdp_type_arg);
946 return -1;
947 }
948
949 if (options.pingcount && options.pdp_type != PDP_EUA_TYPE_v4) {
950 SYS_ERR(DSGSN, LOGL_ERROR, 0, "built-in ping only works with IPv4, use tun-device");
951 return -1;
952 }
Harald Welte840a8e92017-09-24 18:12:40 +0800953
Harald Weltebed35df2011-11-02 13:06:18 +0100954 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000955
956}
957
Harald Welte081f30c2017-10-10 09:36:35 +0800958/* read a single value from a /procc file, up to 255 bytes, callee-allocated */
959static char *proc_read(const char *path)
960{
961 char *ret = NULL;
962 FILE *f;
963
964 f = fopen(path, "r");
965 if (!f)
966 return NULL;
967
968 ret = malloc(256);
969 if (!ret)
970 goto out;
971
972 if (!fgets(ret, 256, f)) {
973 free(ret);
974 ret = NULL;
975 goto out;
976 }
Harald Welte081f30c2017-10-10 09:36:35 +0800977
978out:
979 fclose(f);
980 return ret;
981}
982
983/* Read value of a /proc/sys/net/ipv6/conf file for given device.
984 * Memory is dynamically allocated, caller must free it later. */
985static char *proc_ipv6_conf_read(const char *dev, const char *file)
986{
987 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
Harald Welteb11ed0f2017-11-06 03:07:26 +0900988 char path[strlen(fmt) + strlen(dev) + strlen(file)+1];
Harald Welte081f30c2017-10-10 09:36:35 +0800989 snprintf(path, sizeof(path), fmt, dev, file);
990 return proc_read(path);
991}
992
Harald Weltefed33892017-10-10 09:02:45 +0800993static char *print_ipprot(int t)
Harald Weltebed35df2011-11-02 13:06:18 +0100994{
Harald Weltee37f48e2017-10-10 09:05:50 +0800995 struct protoent *pe = getprotobynumber(t);
996
997 if (!pe)
Harald Weltebed35df2011-11-02 13:06:18 +0100998 return "Unknown";
Harald Weltee37f48e2017-10-10 09:05:50 +0800999 else
1000 return pe->p_name;
jjako5da68452003-01-28 16:08:47 +00001001}
1002
Harald Weltefed33892017-10-10 09:02:45 +08001003static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001004{
1005 static char *ttab[] = {
1006 "Echo Reply",
1007 "ICMP 1",
1008 "ICMP 2",
1009 "Dest Unreachable",
1010 "Source Quench",
1011 "Redirect",
1012 "ICMP 6",
1013 "ICMP 7",
1014 "Echo",
1015 "ICMP 9",
1016 "ICMP 10",
1017 "Time Exceeded",
1018 "Parameter Problem",
1019 "Timestamp",
1020 "Timestamp Reply",
1021 "Info Request",
1022 "Info Reply"
1023 };
1024 if (t < 0 || t > 16)
1025 return ("OUT-OF-RANGE");
1026 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001027}
1028
Harald Weltefed33892017-10-10 09:02:45 +08001029static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001030{
1031 unsigned int n;
1032 uint64_t i64 = 0;
1033 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1034 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001035
Harald Weltebed35df2011-11-02 13:06:18 +01001036 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1037 /* ul16_t format always starts with 0x91 to indicate international format */
1038 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1039 for (n = 0; n < src->l; n++) {
1040 if ((src->v[n] & 0x0f) != 0x0f) {
1041 i64 *= 10;
1042 i64 += src->v[n] & 0x0f;
1043 }
1044 if ((src->v[n] & 0xf0) != 0xf0) {
1045 i64 *= 10;
1046 i64 += (src->v[n] & 0xf0) >> 4;
1047 }
1048 }
jjako193e8b12003-11-10 12:31:41 +00001049
Harald Weltebed35df2011-11-02 13:06:18 +01001050 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001051
Harald Weltebed35df2011-11-02 13:06:18 +01001052 /* Generate array with least significant digit in first octet */
1053 while (i64) {
1054 msa[msalen++] = i64 % 10;
1055 i64 = i64 / 10;
1056 }
jjako193e8b12003-11-10 12:31:41 +00001057
Harald Weltebed35df2011-11-02 13:06:18 +01001058 /* Convert back to ul16_t format */
1059 for (n = 0; n < msalen; n++) {
1060 if ((n % 2) == 0) {
1061 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1062 dst->l += 1;
1063 } else {
1064 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1065 msa[msalen - n - 1] * 16;
1066 }
1067 }
jjako193e8b12003-11-10 12:31:41 +00001068
Harald Weltebed35df2011-11-02 13:06:18 +01001069 return 0;
jjako193e8b12003-11-10 12:31:41 +00001070
1071}
1072
Harald Weltefed33892017-10-10 09:02:45 +08001073static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001074{
1075 /* TODO: big endian / small endian ??? */
1076 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001077
Harald Weltebed35df2011-11-02 13:06:18 +01001078 /* Convert from uint64_t bcd to uint64_t integer format */
1079 /* The resulting integer format is multiplied by 10 */
1080 while (src) {
1081 if ((src & 0x0f) != 0x0f) {
1082 i64 *= 10;
1083 i64 += (src & 0x0f);
1084 }
1085 if ((src & 0xf0) != 0xf0) {
1086 i64 *= 10;
1087 i64 += (src & 0xf0) >> 4;
1088 }
1089 src = src >> 8;
1090 }
jjako193e8b12003-11-10 12:31:41 +00001091
Harald Weltebed35df2011-11-02 13:06:18 +01001092 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001093
Harald Weltebed35df2011-11-02 13:06:18 +01001094 *dst = 0;
1095 while (i64) {
1096 *dst = *dst << 4;
1097 *dst += (i64 % 10);
1098 i64 = i64 / 10;
1099 }
jjako193e8b12003-11-10 12:31:41 +00001100
Harald Weltebed35df2011-11-02 13:06:18 +01001101 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001102
Harald Weltebed35df2011-11-02 13:06:18 +01001103 return 0;
jjako193e8b12003-11-10 12:31:41 +00001104
1105}
1106
jjakoafb2a972003-01-29 21:04:13 +00001107/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001108static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001109{
1110 struct timezone tz;
1111 struct timeval tv;
1112 int diff;
1113 if ((options.pinghost.s_addr) && (2 == state) &&
1114 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1115 gettimeofday(&tv, &tz);
1116 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1117 tp->tv_sec = 0;
1118 if (diff > 0)
1119 tp->tv_usec = diff;
1120 else {
1121 /* For some reason we get packet loss if set to zero */
1122 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1123 tp->tv_usec = 0;
1124 }
1125 }
1126 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001127}
1128
jjako5da68452003-01-28 16:08:47 +00001129/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001130static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001131{
Harald Weltebed35df2011-11-02 13:06:18 +01001132 struct timezone tz;
1133 struct timeval tv;
1134 int elapsed;
1135 gettimeofday(&tv, &tz);
1136 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1137 printf("\n");
1138 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1139 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1140 elapsed / 1000000.0);
1141 printf("%d packets received, ", nreceived);
1142 if (ntransmitted) {
1143 if (nreceived > ntransmitted)
1144 printf("-- somebody's printing up packets!");
1145 else
1146 printf("%d%% packet loss",
1147 (int)(((ntransmitted - nreceived) * 100) /
1148 ntransmitted));
1149 }
1150 printf("\n");
1151 if (options.debug)
1152 printf("%d packets received in total\n", ntreceived);
1153 if (nreceived && tsum)
1154 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1155 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1156 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001157
Harald Weltebed35df2011-11-02 13:06:18 +01001158 ntransmitted = 0;
1159 return 0;
jjako5da68452003-01-28 16:08:47 +00001160}
1161
1162/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltefed33892017-10-10 09:02:45 +08001163static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001164{
1165 struct timezone tz;
1166 struct timeval tv;
1167 struct timeval *tp;
1168 struct ip_ping *pingpack = pack;
1169 struct in_addr src;
1170 int triptime;
jjako5da68452003-01-28 16:08:47 +00001171
Harald Weltebed35df2011-11-02 13:06:18 +01001172 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001173
Harald Weltebed35df2011-11-02 13:06:18 +01001174 gettimeofday(&tv, &tz);
1175 if (options.debug)
1176 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001177
Harald Weltebed35df2011-11-02 13:06:18 +01001178 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1179 printf("packet too short (%d bytes) from %s\n", len,
1180 inet_ntoa(src));
1181 return 0;
1182 }
jjako5da68452003-01-28 16:08:47 +00001183
Harald Weltebed35df2011-11-02 13:06:18 +01001184 ntreceived++;
1185 if (pingpack->protocol != 1) {
1186 if (!options.pingquiet)
1187 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1188 len, inet_ntoa(src), pingpack->protocol,
1189 print_ipprot(pingpack->protocol));
1190 return 0;
1191 }
jjako5da68452003-01-28 16:08:47 +00001192
Harald Weltebed35df2011-11-02 13:06:18 +01001193 if (pingpack->type != 0) {
1194 if (!options.pingquiet)
1195 printf
1196 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1197 len, inet_ntoa(src), pingpack->type,
1198 print_icmptype(pingpack->type), pingpack->code);
1199 return 0;
1200 }
jjako5da68452003-01-28 16:08:47 +00001201
Harald Weltebed35df2011-11-02 13:06:18 +01001202 nreceived++;
1203 if (!options.pingquiet)
1204 printf("%d bytes from %s: icmp_seq=%d", len,
1205 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001206
Harald Weltebed35df2011-11-02 13:06:18 +01001207 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1208 gettimeofday(&tv, &tz);
1209 tp = (struct timeval *)pingpack->data;
1210 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1211 tv.tv_sec--;
1212 tv.tv_usec += 1000000;
1213 }
1214 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001215
Harald Weltebed35df2011-11-02 13:06:18 +01001216 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1217 tsum += triptime;
1218 if (triptime < tmin)
1219 tmin = triptime;
1220 if (triptime > tmax)
1221 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001222
Harald Weltebed35df2011-11-02 13:06:18 +01001223 if (!options.pingquiet)
1224 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001225
Harald Weltebed35df2011-11-02 13:06:18 +01001226 } else if (!options.pingquiet)
1227 printf("\n");
1228 return 0;
jjako5da68452003-01-28 16:08:47 +00001229}
1230
1231/* Create a new ping packet and send it off to peer. */
Harald Weltefed33892017-10-10 09:02:45 +08001232static int create_ping(void *gsn, struct pdp_t *pdp,
1233 struct in_addr *dst, int seq, unsigned int datasize)
Harald Weltebed35df2011-11-02 13:06:18 +01001234{
jjako5da68452003-01-28 16:08:47 +00001235
Harald Weltebed35df2011-11-02 13:06:18 +01001236 struct ip_ping pack;
1237 uint16_t *p = (uint16_t *) & pack;
1238 uint8_t *p8 = (uint8_t *) & pack;
1239 struct in_addr src;
1240 unsigned int n;
1241 long int sum = 0;
1242 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001243
Harald Weltebed35df2011-11-02 13:06:18 +01001244 struct timezone tz;
1245 struct timeval *tp =
1246 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001247
Harald Weltebed35df2011-11-02 13:06:18 +01001248 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001249 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001250 "Ping size to large: %d!", datasize);
1251 return -1;
1252 }
jjako5da68452003-01-28 16:08:47 +00001253
Harald Weltebed35df2011-11-02 13:06:18 +01001254 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001255
Harald Weltebed35df2011-11-02 13:06:18 +01001256 pack.ipver = 0x45;
1257 pack.tos = 0x00;
1258 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1259 pack.fragid = 0x0000;
1260 pack.offset = 0x0040;
1261 pack.ttl = 0x40;
1262 pack.protocol = 0x01;
1263 pack.ipcheck = 0x0000;
1264 pack.src = src.s_addr;
1265 pack.dst = dst->s_addr;
1266 pack.type = 0x08;
1267 pack.code = 0x00;
1268 pack.checksum = 0x0000;
1269 pack.ident = 0x0000;
1270 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001271
Harald Weltebed35df2011-11-02 13:06:18 +01001272 /* Generate ICMP payload */
1273 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1274 for (n = 0; n < (datasize); n++)
1275 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001276
Harald Weltebed35df2011-11-02 13:06:18 +01001277 if (datasize >= sizeof(struct timeval))
1278 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001279
Harald Weltebed35df2011-11-02 13:06:18 +01001280 /* Calculate IP header checksum */
1281 p = (uint16_t *) & pack;
1282 count = CREATEPING_IP;
1283 sum = 0;
1284 while (count > 1) {
1285 sum += *p++;
1286 count -= 2;
1287 }
1288 while (sum >> 16)
1289 sum = (sum & 0xffff) + (sum >> 16);
1290 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001291
Harald Weltebed35df2011-11-02 13:06:18 +01001292 /* Calculate ICMP checksum */
1293 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1294 sum = 0;
1295 p = (uint16_t *) & pack;
1296 p += CREATEPING_IP / 2;
1297 while (count > 1) {
1298 sum += *p++;
1299 count -= 2;
1300 }
1301 if (count > 0)
1302 sum += *(unsigned char *)p;
1303 while (sum >> 16)
1304 sum = (sum & 0xffff) + (sum >> 16);
1305 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001306
Harald Weltebed35df2011-11-02 13:06:18 +01001307 ntransmitted++;
1308 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001309}
1310
Harald Weltefed33892017-10-10 09:02:45 +08001311static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001312{
1313
1314 if (tun && options.ipdown)
1315 tun_runscript(tun, options.ipdown);
1316
Pau Espin Pedroldbeaa042018-02-12 19:11:28 +01001317 ipdel((struct iphash_t *)pdp->peer[0]);
1318 memset(pdp->peer[0], 0, sizeof(struct iphash_t)); /* To be sure */
Harald Weltebed35df2011-11-02 13:06:18 +01001319
1320 if (1 == options.contexts)
1321 state = 5; /* Disconnected */
1322
1323 return 0;
1324}
jjakoa7cd2492003-04-11 09:40:12 +00001325
Harald Welte6748dc92017-09-24 21:54:59 +08001326/* Link-Local address prefix fe80::/64 */
1327static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1328
jjakoa7cd2492003-04-11 09:40:12 +00001329/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001330static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001331{
1332 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001333 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001334 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001335 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001336
Harald Welte6748dc92017-09-24 21:54:59 +08001337 if (iph->version == 4) {
1338 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1339 printf("Dropping packet with too short IP header\n");
1340 return 0;
1341 }
1342 src.len = 4;
1343 src.v4.s_addr = iph->saddr;
1344 } else if (iph->version == 6) {
1345 /* We only have a single entry in the hash table, and it consists of the link-local
1346 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1347 * addresses to that format before looking up the hash table via ippool_getip() */
1348 src.len = 16;
1349 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1350 /* is a link-local address, we can do the hash lookup 1:1 */
1351 src.v6 = ip6h->ip6_src;
1352 } else {
1353 /* it is not a link-local address, so we must convert from the /64 prefix
1354 * to the link-local format that's used in the hash table */
1355 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1356 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1357 }
1358 } else {
1359 printf("Dropping packet with invalid IP version %u\n", iph->version);
1360 return 0;
1361 }
jjakoa7cd2492003-04-11 09:40:12 +00001362
Harald Weltebed35df2011-11-02 13:06:18 +01001363 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001364 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001365 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001366 return 0;
1367 }
1368
1369 if (ipm->pdp) /* Check if a peer protocol is defined */
1370 gtp_data_req(gsn, ipm->pdp, pack, len);
1371 return 0;
jjako52c24142002-12-16 13:33:51 +00001372}
1373
Harald Weltefed33892017-10-10 09:02:45 +08001374static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001375{
Harald Welted12eab92017-08-02 19:49:47 +02001376 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001377
Harald Weltebed35df2011-11-02 13:06:18 +01001378 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001379
Harald Weltebed35df2011-11-02 13:06:18 +01001380 if (cause < 0) {
1381 printf("Create PDP Context Request timed out\n");
1382 if (iph->pdp->version == 1) {
1383 printf("Retrying with version 0\n");
1384 iph->pdp->version = 0;
1385 gtp_create_context_req(gsn, iph->pdp, iph);
1386 return 0;
1387 } else {
1388 state = 0;
1389 pdp_freepdp(iph->pdp);
1390 iph->pdp = NULL;
1391 return EOF;
1392 }
1393 }
jjako2c381332003-10-21 19:09:53 +00001394
Harald Weltebed35df2011-11-02 13:06:18 +01001395 if (cause != 128) {
1396 printf
1397 ("Received create PDP context response. Cause value: %d\n",
1398 cause);
1399 state = 0;
1400 pdp_freepdp(iph->pdp);
1401 iph->pdp = NULL;
1402 return EOF; /* Not what we expected */
1403 }
jjako52c24142002-12-16 13:33:51 +00001404
Viktor Tsymbalyuka2a08f72018-01-26 12:47:55 +02001405 if (in46a_from_eua(&pdp->eua, &addr) < 1) {
Harald Weltebed35df2011-11-02 13:06:18 +01001406 printf
1407 ("Received create PDP context response. Cause value: %d\n",
1408 cause);
1409 pdp_freepdp(iph->pdp);
1410 iph->pdp = NULL;
1411 state = 0;
1412 return EOF; /* Not a valid IP address */
1413 }
jjakoa7cd2492003-04-11 09:40:12 +00001414
Harald Weltebed35df2011-11-02 13:06:18 +01001415 printf("Received create PDP context response. IP address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001416 in46a_ntoa(&addr));
1417
1418 switch (addr.len) {
1419 case 16: /* IPv6 */
1420 /* we have to enable the kernel to perform stateless autoconfiguration,
1421 * i.e. send a router solicitation using the lover 64bits of the allocated
1422 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1423 memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1424 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
1425 break;
1426 case 4: /* IPv4 */
1427 break;
1428 }
jjakoa7cd2492003-04-11 09:40:12 +00001429
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001430 if ((options.createif) && (!options.net.len)) {
Harald Welte6748dc92017-09-24 21:54:59 +08001431 size_t prefixlen = 32;
1432 if (addr.len == 16)
1433 prefixlen = 64;
Harald Weltebed35df2011-11-02 13:06:18 +01001434 /* printf("Setting up interface and routing\n"); */
Harald Welte31e1dab2018-04-25 17:53:30 +02001435 tun_addaddr(tun, &addr, &addr, prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001436 if (options.defaultroute) {
1437 struct in_addr rm;
1438 rm.s_addr = 0;
Harald Welteb4c08282018-04-25 16:55:39 +02001439 netdev_addroute(&rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001440 }
1441 if (options.ipup)
1442 tun_runscript(tun, options.ipup);
1443 }
jjako52c24142002-12-16 13:33:51 +00001444
Harald Welte081f30c2017-10-10 09:36:35 +08001445 /* now that ip-up has been executed, check if we are configured to
1446 * accept router advertisements */
1447 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
1448 char *accept_ra, *forwarding;
1449
1450 accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
1451 forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
1452 if (!accept_ra || !forwarding)
1453 printf("Could not open proc file for %s ?!?\n", tun->devname);
1454 else {
1455 if (!strcmp(accept_ra, "0") ||
1456 (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1"))) {
1457 printf("%s is %s, i.e. your tun device is not configured to accept "
1458 "router advertisements; SLAAC will not suceed, please "
1459 "fix your setup!\n");
1460 }
Harald Welte081f30c2017-10-10 09:36:35 +08001461 }
Harald Welteb589e782017-11-06 03:09:35 +09001462 free(accept_ra);
1463 free(forwarding);
Harald Welte081f30c2017-10-10 09:36:35 +08001464 }
1465
Viktor Tsymbalyuk7ad4d5e2018-02-12 14:00:45 +02001466 ipset(iph, &addr);
Harald Weltebed35df2011-11-02 13:06:18 +01001467
1468 state = 2; /* Connected */
1469
1470 return 0;
jjako52c24142002-12-16 13:33:51 +00001471}
1472
Harald Weltefed33892017-10-10 09:02:45 +08001473static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001474{
1475 printf("Received delete PDP context response. Cause value: %d\n",
1476 cause);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001477 if (pdp)
1478 pdp_freepdp(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001479 return 0;
jjako52c24142002-12-16 13:33:51 +00001480}
1481
Harald Weltefed33892017-10-10 09:02:45 +08001482static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001483{
jjako91aaf222003-10-22 10:09:32 +00001484
Harald Weltebed35df2011-11-02 13:06:18 +01001485 if (recovery < 0) {
1486 printf("Echo Request timed out\n");
1487 if (echoversion == 1) {
1488 printf("Retrying with version 0\n");
1489 echoversion = 0;
1490 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1491 return 0;
1492 } else {
1493 state = 0;
1494 return EOF;
1495 }
1496 } else {
1497 printf("Received echo response\n");
1498 if (!options.contexts)
1499 state = 5;
1500 }
1501 return 0;
jjako52c24142002-12-16 13:33:51 +00001502}
1503
Harald Weltefed33892017-10-10 09:02:45 +08001504static int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001505{
1506 /* if (cause < 0) return 0; Some error occurred. We don't care */
1507 switch (type) {
1508 case GTP_ECHO_REQ:
1509 return echo_conf(cause);
1510 case GTP_CREATE_PDP_REQ:
1511 return create_pdp_conf(pdp, cbp, cause);
1512 case GTP_DELETE_PDP_REQ:
Harald Weltebed35df2011-11-02 13:06:18 +01001513 return delete_pdp_conf(pdp, cause);
1514 default:
1515 return 0;
1516 }
jjako52c24142002-12-16 13:33:51 +00001517}
1518
Harald Weltefed33892017-10-10 09:02:45 +08001519static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001520{
1521 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1522 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001523}
1524
1525int main(int argc, char **argv)
1526{
Harald Weltebed35df2011-11-02 13:06:18 +01001527 fd_set fds; /* For select() */
1528 struct timeval idleTime; /* How long to select() */
1529 struct pdp_t *pdp;
1530 int n;
1531 int starttime = time(NULL); /* Time program was started */
1532 int stoptime = 0; /* Time to exit */
1533 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001534 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001535
Harald Weltebed35df2011-11-02 13:06:18 +01001536 struct timezone tz; /* Used for calculating ping times */
1537 struct timeval tv;
1538 int diff;
jjako52c24142002-12-16 13:33:51 +00001539
bjovana8f71eb2017-02-24 17:39:20 +01001540 signal(SIGTERM, signal_handler);
1541 signal(SIGHUP, signal_handler);
1542 signal(SIGINT, signal_handler);
1543
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001544 tall_sgsnemu_ctx = talloc_named_const(NULL, 0, "sgsnemu");
1545 msgb_talloc_ctx_init(tall_sgsnemu_ctx, 0);
1546 osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
jjako0141d202004-01-09 15:19:20 +00001547
Harald Weltebed35df2011-11-02 13:06:18 +01001548 /* Process options given in configuration file and command line */
1549 if (process_options(argc, argv))
1550 exit(1);
jjako52c24142002-12-16 13:33:51 +00001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 printf("\nInitialising GTP library\n");
1553 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001554 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001555 exit(1);
1556 }
1557 if (gsn->fd0 > maxfd)
1558 maxfd = gsn->fd0;
1559 if (gsn->fd1c > maxfd)
1560 maxfd = gsn->fd1c;
1561 if (gsn->fd1u > maxfd)
1562 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001563
Harald Weltebed35df2011-11-02 13:06:18 +01001564 gtp_set_cb_delete_context(gsn, delete_context);
1565 gtp_set_cb_conf(gsn, conf);
1566 if (options.createif)
1567 gtp_set_cb_data_ind(gsn, encaps_tun);
1568 else
1569 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001570
Harald Weltebed35df2011-11-02 13:06:18 +01001571 if (options.createif) {
1572 printf("Setting up interface\n");
1573 /* Create a tunnel interface */
Harald Weltef2286392018-04-25 19:02:31 +02001574 if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001575 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001576 "Failed to create tun");
1577 exit(1);
1578 }
1579 tun_set_cb_ind(tun, cb_tun_ind);
1580 if (tun->fd > maxfd)
1581 maxfd = tun->fd;
1582 }
jjakoa7cd2492003-04-11 09:40:12 +00001583
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001584 if ((options.createif) && (options.net.len)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001585 /* printf("Setting up interface and routing\n"); */
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001586 tun_addaddr(tun, &options.netaddr, &options.destaddr, options.prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001587 if (options.defaultroute) {
1588 struct in_addr rm;
1589 rm.s_addr = 0;
Harald Welteb4c08282018-04-25 16:55:39 +02001590 netdev_addroute(&rm, &options.destaddr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001591 }
1592 if (options.ipup)
1593 tun_runscript(tun, options.ipup);
1594 }
jjakoa7cd2492003-04-11 09:40:12 +00001595
Harald Weltebed35df2011-11-02 13:06:18 +01001596 /* Initialise hash tables */
1597 memset(&iphash, 0, sizeof(iphash));
1598 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001599
Harald Weltebed35df2011-11-02 13:06:18 +01001600 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001601
Harald Weltebed35df2011-11-02 13:06:18 +01001602 /* See if anybody is there */
1603 printf("Sending off echo request\n");
1604 echoversion = options.gtpversion;
1605 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001606
Harald Weltebed35df2011-11-02 13:06:18 +01001607 for (n = 0; n < options.contexts; n++) {
1608 uint64_t myimsi;
1609 printf("Setting up PDP context #%d\n", n);
1610 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001611
Harald Weltebed35df2011-11-02 13:06:18 +01001612 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001613
Harald Weltebed35df2011-11-02 13:06:18 +01001614 /* Allocated here. */
1615 /* If create context failes we have to deallocate ourselves. */
1616 /* Otherwise it is deallocated by gtplib */
Pau Espin Pedrold1a2ddf2019-05-31 16:17:27 +02001617 gtp_pdp_newpdp(gsn, &pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001618
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +01001619 pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
Harald Weltebed35df2011-11-02 13:06:18 +01001620 pdp->ipif = tun; /* TODO */
1621 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001622
Harald Weltebed35df2011-11-02 13:06:18 +01001623 if (options.gtpversion == 0) {
1624 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001625 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001626 "QoS length too big");
1627 exit(1);
1628 } else {
1629 memcpy(pdp->qos_req0, options.qos.v,
1630 options.qos.l);
1631 }
1632 }
jjakoa7cd2492003-04-11 09:40:12 +00001633
Harald Weltebed35df2011-11-02 13:06:18 +01001634 pdp->qos_req.l = options.qos.l;
1635 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001636
Harald Weltebed35df2011-11-02 13:06:18 +01001637 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001638
Harald Weltebed35df2011-11-02 13:06:18 +01001639 pdp->rattype.l = options.rattype.l;
1640 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1641 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001642
Harald Weltebed35df2011-11-02 13:06:18 +01001643 pdp->userloc.l = options.userloc.l;
1644 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1645 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001646
Harald Weltebed35df2011-11-02 13:06:18 +01001647 pdp->rai.l = options.rai.l;
1648 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1649 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001650
Harald Weltebed35df2011-11-02 13:06:18 +01001651 pdp->mstz.l = options.mstz.l;
1652 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1653 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001654
Harald Weltebed35df2011-11-02 13:06:18 +01001655 pdp->imeisv.l = options.imeisv.l;
1656 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1657 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001658
Harald Weltebed35df2011-11-02 13:06:18 +01001659 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001660
Harald Weltebed35df2011-11-02 13:06:18 +01001661 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001662 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001663 "APN length too big");
1664 exit(1);
1665 } else {
1666 pdp->apn_use.l = options.apn.l;
1667 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1668 }
jjako193e8b12003-11-10 12:31:41 +00001669
Harald Weltebed35df2011-11-02 13:06:18 +01001670 pdp->gsnlc.l = sizeof(options.listen);
1671 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1672 pdp->gsnlu.l = sizeof(options.listen);
1673 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001674
Harald Weltebed35df2011-11-02 13:06:18 +01001675 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001676 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001677 "MSISDN length too big");
1678 exit(1);
1679 } else {
1680 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1681 }
jjakob62c3dd2004-05-27 18:51:55 +00001682
Harald Welte840a8e92017-09-24 18:12:40 +08001683 /* Request dynamic IP address */
1684 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1685 pdp->eua.v[1] = options.pdp_type;
1686 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001687
Harald Weltebed35df2011-11-02 13:06:18 +01001688 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001689 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001690 "PCO length too big");
1691 exit(1);
1692 } else {
1693 pdp->pco_req.l = options.pco.l;
1694 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1695 }
jjako52c24142002-12-16 13:33:51 +00001696
Harald Weltebed35df2011-11-02 13:06:18 +01001697 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001698
Harald Weltebed35df2011-11-02 13:06:18 +01001699 pdp->hisaddr0 = options.remote;
1700 pdp->hisaddr1 = options.remote;
1701
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01001702 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
Harald Weltebed35df2011-11-02 13:06:18 +01001703 512 = Flat rate, 256 = Hot billing */
1704
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001705 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1706
Harald Weltebed35df2011-11-02 13:06:18 +01001707 /* Create context */
1708 /* We send this of once. Retransmissions are handled by gtplib */
1709 gtp_create_context_req(gsn, pdp, &iparr[n]);
1710 }
1711
1712 state = 1; /* Enter wait_connection state */
1713
1714 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001715
jjako52c24142002-12-16 13:33:51 +00001716 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001717 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001718 /******************************************************************/
1719
Harald Weltebed35df2011-11-02 13:06:18 +01001720 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001721
Harald Weltebed35df2011-11-02 13:06:18 +01001722 /* Take down client after timeout after disconnect */
1723 if ((4 == state) && ((stoptime) <= time(NULL))) {
1724 state = 5;
1725 }
jjako7b8fad42003-07-07 14:37:42 +00001726
Harald Weltebed35df2011-11-02 13:06:18 +01001727 /* Take down client after timelimit timeout */
1728 if ((2 == state) && (options.timelimit) &&
1729 ((starttime + options.timelimit) <= time(NULL))) {
1730 state = 3;
1731 }
jjako7b8fad42003-07-07 14:37:42 +00001732
Harald Weltebed35df2011-11-02 13:06:18 +01001733 /* Take down client after ping timeout */
1734 if ((2 == state) && (pingtimeout)
1735 && (pingtimeout <= time(NULL))) {
1736 state = 3;
1737 }
jjako7b8fad42003-07-07 14:37:42 +00001738
Harald Weltebed35df2011-11-02 13:06:18 +01001739 /* Set pingtimeout for later disconnection */
1740 if (options.pingcount && ntransmitted >= options.pingcount) {
1741 pingtimeout = time(NULL) + 5; /* Extra seconds */
1742 }
jjako7b8fad42003-07-07 14:37:42 +00001743
Harald Weltebed35df2011-11-02 13:06:18 +01001744 /* Print statistics if no more ping packets are missing */
1745 if (ntransmitted && options.pingcount
1746 && nreceived >= options.pingcount) {
1747 ping_finish();
1748 if (!options.createif)
1749 state = 3;
1750 }
jjako7b8fad42003-07-07 14:37:42 +00001751
Harald Weltebed35df2011-11-02 13:06:18 +01001752 /* Send off disconnect */
1753 if (3 == state) {
1754 state = 4;
1755 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1756 for (n = 0; n < options.contexts; n++) {
1757 /* Delete context */
1758 printf("Disconnecting PDP context #%d\n", n);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001759 gtp_delete_context_req2(gsn, iparr[n].pdp, NULL, 1);
Harald Weltebed35df2011-11-02 13:06:18 +01001760 if ((options.pinghost.s_addr != 0)
1761 && ntransmitted)
1762 ping_finish();
1763 }
1764 }
jjako7b8fad42003-07-07 14:37:42 +00001765
Harald Weltebed35df2011-11-02 13:06:18 +01001766 /* Send of ping packets */
1767 diff = 0;
1768 while ((diff <= 0) &&
1769 /* Send off an ICMP ping packet */
1770 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1771 ((pingseq < options.pingcount)
1772 || (options.pingcount == 0))) {
1773 if (!pingseq)
1774 gettimeofday(&firstping, &tz); /* Set time of first ping */
1775 gettimeofday(&tv, &tz);
1776 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1777 if (diff <= 0) {
1778 if (options.debug)
1779 printf("Create_ping %d\n", diff);
1780 create_ping(gsn,
1781 iparr[pingseq %
1782 options.contexts].pdp,
1783 &options.pinghost, pingseq,
1784 options.pingsize);
1785 pingseq++;
1786 }
1787 }
jjako5da68452003-01-28 16:08:47 +00001788
Harald Weltebed35df2011-11-02 13:06:18 +01001789 FD_ZERO(&fds);
1790 if (tun)
1791 FD_SET(tun->fd, &fds);
1792 FD_SET(gsn->fd0, &fds);
1793 FD_SET(gsn->fd1c, &fds);
1794 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001795
Harald Weltebed35df2011-11-02 13:06:18 +01001796 gtp_retranstimeout(gsn, &idleTime);
1797 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001798
Harald Weltebed35df2011-11-02 13:06:18 +01001799 if (options.debug)
1800 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1801 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001802
bjovana8f71eb2017-02-24 17:39:20 +01001803 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001804 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1805 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001806 if (errno == EINTR)
1807 signal_received = 1;
1808 else
1809 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1810 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001811 break;
1812 case 0:
1813 gtp_retrans(gsn); /* Only retransmit if nothing else */
1814 break;
1815 default:
1816 break;
1817 }
1818
bjovana8f71eb2017-02-24 17:39:20 +01001819 if (!signal_received) {
1820
1821 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1822 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1823 "TUN decaps failed");
1824 }
1825
1826 if (FD_ISSET(gsn->fd0, &fds))
1827 gtp_decaps0(gsn);
1828
1829 if (FD_ISSET(gsn->fd1c, &fds))
1830 gtp_decaps1c(gsn);
1831
1832 if (FD_ISSET(gsn->fd1u, &fds))
1833 gtp_decaps1u(gsn);
1834
Harald Weltebed35df2011-11-02 13:06:18 +01001835 }
Harald Weltebed35df2011-11-02 13:06:18 +01001836 }
1837
1838 gtp_free(gsn); /* Clean up the gsn instance */
1839
1840 if (options.createif)
1841 tun_free(tun);
1842
1843 if (0 == state)
1844 exit(1); /* Indicate error */
1845
1846 return 0;
jjako52c24142002-12-16 13:33:51 +00001847}