blob: 4f1f844d53ed845e8da49b9b17752b35c37c8359 [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;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001237 uint16_t v16;
Harald Weltebed35df2011-11-02 13:06:18 +01001238 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 */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001273 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
Harald Weltebed35df2011-11-02 13:06:18 +01001274 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 */
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001281 p8 = (uint8_t *) &pack;
Harald Weltebed35df2011-11-02 13:06:18 +01001282 count = CREATEPING_IP;
1283 sum = 0;
1284 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001285 memcpy(&v16, p8, 2);
1286 sum += v16;
1287 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001288 count -= 2;
1289 }
1290 while (sum >> 16)
1291 sum = (sum & 0xffff) + (sum >> 16);
1292 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001293
Harald Weltebed35df2011-11-02 13:06:18 +01001294 /* Calculate ICMP checksum */
1295 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1296 sum = 0;
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001297 p8 = (uint8_t *) &pack;
1298 p8 += CREATEPING_IP;
Harald Weltebed35df2011-11-02 13:06:18 +01001299 while (count > 1) {
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001300 memcpy(&v16, p8, 2);
1301 sum += v16;
1302 p8 += 2;
Harald Weltebed35df2011-11-02 13:06:18 +01001303 count -= 2;
1304 }
1305 if (count > 0)
Pau Espin Pedrole4793292019-07-29 18:03:04 +02001306 sum += *(unsigned char *)p8;
Harald Weltebed35df2011-11-02 13:06:18 +01001307 while (sum >> 16)
1308 sum = (sum & 0xffff) + (sum >> 16);
1309 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001310
Harald Weltebed35df2011-11-02 13:06:18 +01001311 ntransmitted++;
1312 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001313}
1314
Harald Weltefed33892017-10-10 09:02:45 +08001315static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001316{
1317
1318 if (tun && options.ipdown)
1319 tun_runscript(tun, options.ipdown);
1320
Pau Espin Pedroldbeaa042018-02-12 19:11:28 +01001321 ipdel((struct iphash_t *)pdp->peer[0]);
1322 memset(pdp->peer[0], 0, sizeof(struct iphash_t)); /* To be sure */
Harald Weltebed35df2011-11-02 13:06:18 +01001323
1324 if (1 == options.contexts)
1325 state = 5; /* Disconnected */
1326
1327 return 0;
1328}
jjakoa7cd2492003-04-11 09:40:12 +00001329
Harald Welte6748dc92017-09-24 21:54:59 +08001330/* Link-Local address prefix fe80::/64 */
1331static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1332
jjakoa7cd2492003-04-11 09:40:12 +00001333/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001334static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001335{
1336 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001337 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001338 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001339 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001340
Harald Welte6748dc92017-09-24 21:54:59 +08001341 if (iph->version == 4) {
1342 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1343 printf("Dropping packet with too short IP header\n");
1344 return 0;
1345 }
1346 src.len = 4;
1347 src.v4.s_addr = iph->saddr;
1348 } else if (iph->version == 6) {
1349 /* We only have a single entry in the hash table, and it consists of the link-local
1350 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1351 * addresses to that format before looking up the hash table via ippool_getip() */
1352 src.len = 16;
1353 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1354 /* is a link-local address, we can do the hash lookup 1:1 */
1355 src.v6 = ip6h->ip6_src;
1356 } else {
1357 /* it is not a link-local address, so we must convert from the /64 prefix
1358 * to the link-local format that's used in the hash table */
1359 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1360 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1361 }
1362 } else {
1363 printf("Dropping packet with invalid IP version %u\n", iph->version);
1364 return 0;
1365 }
jjakoa7cd2492003-04-11 09:40:12 +00001366
Harald Weltebed35df2011-11-02 13:06:18 +01001367 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001368 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001369 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001370 return 0;
1371 }
1372
1373 if (ipm->pdp) /* Check if a peer protocol is defined */
1374 gtp_data_req(gsn, ipm->pdp, pack, len);
1375 return 0;
jjako52c24142002-12-16 13:33:51 +00001376}
1377
Harald Weltefed33892017-10-10 09:02:45 +08001378static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001379{
Harald Welted12eab92017-08-02 19:49:47 +02001380 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001381
Harald Weltebed35df2011-11-02 13:06:18 +01001382 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001383
Harald Weltebed35df2011-11-02 13:06:18 +01001384 if (cause < 0) {
1385 printf("Create PDP Context Request timed out\n");
1386 if (iph->pdp->version == 1) {
1387 printf("Retrying with version 0\n");
1388 iph->pdp->version = 0;
1389 gtp_create_context_req(gsn, iph->pdp, iph);
1390 return 0;
1391 } else {
1392 state = 0;
1393 pdp_freepdp(iph->pdp);
1394 iph->pdp = NULL;
1395 return EOF;
1396 }
1397 }
jjako2c381332003-10-21 19:09:53 +00001398
Harald Weltebed35df2011-11-02 13:06:18 +01001399 if (cause != 128) {
1400 printf
1401 ("Received create PDP context response. Cause value: %d\n",
1402 cause);
1403 state = 0;
1404 pdp_freepdp(iph->pdp);
1405 iph->pdp = NULL;
1406 return EOF; /* Not what we expected */
1407 }
jjako52c24142002-12-16 13:33:51 +00001408
Viktor Tsymbalyuka2a08f72018-01-26 12:47:55 +02001409 if (in46a_from_eua(&pdp->eua, &addr) < 1) {
Harald Weltebed35df2011-11-02 13:06:18 +01001410 printf
1411 ("Received create PDP context response. Cause value: %d\n",
1412 cause);
1413 pdp_freepdp(iph->pdp);
1414 iph->pdp = NULL;
1415 state = 0;
1416 return EOF; /* Not a valid IP address */
1417 }
jjakoa7cd2492003-04-11 09:40:12 +00001418
Harald Weltebed35df2011-11-02 13:06:18 +01001419 printf("Received create PDP context response. IP address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001420 in46a_ntoa(&addr));
1421
1422 switch (addr.len) {
1423 case 16: /* IPv6 */
1424 /* we have to enable the kernel to perform stateless autoconfiguration,
1425 * i.e. send a router solicitation using the lover 64bits of the allocated
1426 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1427 memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1428 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
1429 break;
1430 case 4: /* IPv4 */
1431 break;
1432 }
jjakoa7cd2492003-04-11 09:40:12 +00001433
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001434 if ((options.createif) && (!options.net.len)) {
Harald Welte6748dc92017-09-24 21:54:59 +08001435 size_t prefixlen = 32;
1436 if (addr.len == 16)
1437 prefixlen = 64;
Harald Weltebed35df2011-11-02 13:06:18 +01001438 /* printf("Setting up interface and routing\n"); */
Harald Welte31e1dab2018-04-25 17:53:30 +02001439 tun_addaddr(tun, &addr, &addr, prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001440 if (options.defaultroute) {
1441 struct in_addr rm;
1442 rm.s_addr = 0;
Harald Welteb4c08282018-04-25 16:55:39 +02001443 netdev_addroute(&rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001444 }
1445 if (options.ipup)
1446 tun_runscript(tun, options.ipup);
1447 }
jjako52c24142002-12-16 13:33:51 +00001448
Harald Welte081f30c2017-10-10 09:36:35 +08001449 /* now that ip-up has been executed, check if we are configured to
1450 * accept router advertisements */
1451 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
1452 char *accept_ra, *forwarding;
1453
1454 accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
1455 forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
1456 if (!accept_ra || !forwarding)
1457 printf("Could not open proc file for %s ?!?\n", tun->devname);
1458 else {
Harald Weltef1e01512019-07-21 12:36:27 +02001459 if (!strcmp(accept_ra, "0")) {
1460 printf("accept_ra=0, i.e. your tun device is not configured to accept "
1461 "router advertisements; SLAAC will not succeed, please "
Harald Welte081f30c2017-10-10 09:36:35 +08001462 "fix your setup!\n");
1463 }
Harald Weltef1e01512019-07-21 12:36:27 +02001464 if (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1")) {
1465 printf("forwarding=1 and accept_ra=1, i.e. your tun device is not "
1466 "configured to accept router advertisements; SLAAC will not "
1467 "succeed, please fix your setup!\n");
1468 }
Harald Welte081f30c2017-10-10 09:36:35 +08001469 }
Harald Welteb589e782017-11-06 03:09:35 +09001470 free(accept_ra);
1471 free(forwarding);
Harald Welte081f30c2017-10-10 09:36:35 +08001472 }
1473
Viktor Tsymbalyuk7ad4d5e2018-02-12 14:00:45 +02001474 ipset(iph, &addr);
Harald Weltebed35df2011-11-02 13:06:18 +01001475
1476 state = 2; /* Connected */
1477
1478 return 0;
jjako52c24142002-12-16 13:33:51 +00001479}
1480
Harald Weltefed33892017-10-10 09:02:45 +08001481static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001482{
1483 printf("Received delete PDP context response. Cause value: %d\n",
1484 cause);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001485 if (pdp)
1486 pdp_freepdp(pdp);
Harald Weltebed35df2011-11-02 13:06:18 +01001487 return 0;
jjako52c24142002-12-16 13:33:51 +00001488}
1489
Harald Weltefed33892017-10-10 09:02:45 +08001490static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001491{
jjako91aaf222003-10-22 10:09:32 +00001492
Harald Weltebed35df2011-11-02 13:06:18 +01001493 if (recovery < 0) {
1494 printf("Echo Request timed out\n");
1495 if (echoversion == 1) {
1496 printf("Retrying with version 0\n");
1497 echoversion = 0;
1498 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1499 return 0;
1500 } else {
1501 state = 0;
1502 return EOF;
1503 }
1504 } else {
1505 printf("Received echo response\n");
1506 if (!options.contexts)
1507 state = 5;
1508 }
1509 return 0;
jjako52c24142002-12-16 13:33:51 +00001510}
1511
Harald Weltefed33892017-10-10 09:02:45 +08001512static int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001513{
1514 /* if (cause < 0) return 0; Some error occurred. We don't care */
1515 switch (type) {
1516 case GTP_ECHO_REQ:
1517 return echo_conf(cause);
1518 case GTP_CREATE_PDP_REQ:
1519 return create_pdp_conf(pdp, cbp, cause);
1520 case GTP_DELETE_PDP_REQ:
Harald Weltebed35df2011-11-02 13:06:18 +01001521 return delete_pdp_conf(pdp, cause);
1522 default:
1523 return 0;
1524 }
jjako52c24142002-12-16 13:33:51 +00001525}
1526
Harald Weltefed33892017-10-10 09:02:45 +08001527static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001528{
1529 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1530 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001531}
1532
1533int main(int argc, char **argv)
1534{
Harald Weltebed35df2011-11-02 13:06:18 +01001535 fd_set fds; /* For select() */
1536 struct timeval idleTime; /* How long to select() */
1537 struct pdp_t *pdp;
1538 int n;
1539 int starttime = time(NULL); /* Time program was started */
1540 int stoptime = 0; /* Time to exit */
1541 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001542 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001543
Harald Weltebed35df2011-11-02 13:06:18 +01001544 struct timezone tz; /* Used for calculating ping times */
1545 struct timeval tv;
1546 int diff;
jjako52c24142002-12-16 13:33:51 +00001547
bjovana8f71eb2017-02-24 17:39:20 +01001548 signal(SIGTERM, signal_handler);
1549 signal(SIGHUP, signal_handler);
1550 signal(SIGINT, signal_handler);
1551
Pau Espin Pedrol042a4452018-04-17 14:31:42 +02001552 tall_sgsnemu_ctx = talloc_named_const(NULL, 0, "sgsnemu");
1553 msgb_talloc_ctx_init(tall_sgsnemu_ctx, 0);
1554 osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
jjako0141d202004-01-09 15:19:20 +00001555
Harald Weltebed35df2011-11-02 13:06:18 +01001556 /* Process options given in configuration file and command line */
1557 if (process_options(argc, argv))
1558 exit(1);
jjako52c24142002-12-16 13:33:51 +00001559
Harald Weltebed35df2011-11-02 13:06:18 +01001560 printf("\nInitialising GTP library\n");
1561 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001562 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001563 exit(1);
1564 }
1565 if (gsn->fd0 > maxfd)
1566 maxfd = gsn->fd0;
1567 if (gsn->fd1c > maxfd)
1568 maxfd = gsn->fd1c;
1569 if (gsn->fd1u > maxfd)
1570 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001571
Harald Weltebed35df2011-11-02 13:06:18 +01001572 gtp_set_cb_delete_context(gsn, delete_context);
1573 gtp_set_cb_conf(gsn, conf);
1574 if (options.createif)
1575 gtp_set_cb_data_ind(gsn, encaps_tun);
1576 else
1577 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001578
Harald Weltebed35df2011-11-02 13:06:18 +01001579 if (options.createif) {
1580 printf("Setting up interface\n");
1581 /* Create a tunnel interface */
Harald Weltef2286392018-04-25 19:02:31 +02001582 if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001583 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001584 "Failed to create tun");
1585 exit(1);
1586 }
1587 tun_set_cb_ind(tun, cb_tun_ind);
1588 if (tun->fd > maxfd)
1589 maxfd = tun->fd;
1590 }
jjakoa7cd2492003-04-11 09:40:12 +00001591
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001592 if ((options.createif) && (options.net.len)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001593 /* printf("Setting up interface and routing\n"); */
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001594 tun_addaddr(tun, &options.netaddr, &options.destaddr, options.prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001595 if (options.defaultroute) {
1596 struct in_addr rm;
1597 rm.s_addr = 0;
Harald Welteb4c08282018-04-25 16:55:39 +02001598 netdev_addroute(&rm, &options.destaddr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001599 }
1600 if (options.ipup)
1601 tun_runscript(tun, options.ipup);
1602 }
jjakoa7cd2492003-04-11 09:40:12 +00001603
Harald Weltebed35df2011-11-02 13:06:18 +01001604 /* Initialise hash tables */
1605 memset(&iphash, 0, sizeof(iphash));
1606 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001607
Harald Weltebed35df2011-11-02 13:06:18 +01001608 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001609
Harald Weltebed35df2011-11-02 13:06:18 +01001610 /* See if anybody is there */
1611 printf("Sending off echo request\n");
1612 echoversion = options.gtpversion;
1613 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001614
Harald Weltebed35df2011-11-02 13:06:18 +01001615 for (n = 0; n < options.contexts; n++) {
1616 uint64_t myimsi;
1617 printf("Setting up PDP context #%d\n", n);
1618 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001619
Harald Weltebed35df2011-11-02 13:06:18 +01001620 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001621
Harald Weltebed35df2011-11-02 13:06:18 +01001622 /* Allocated here. */
1623 /* If create context failes we have to deallocate ourselves. */
1624 /* Otherwise it is deallocated by gtplib */
Pau Espin Pedrold1a2ddf2019-05-31 16:17:27 +02001625 gtp_pdp_newpdp(gsn, &pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001626
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +01001627 pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
Harald Weltebed35df2011-11-02 13:06:18 +01001628 pdp->ipif = tun; /* TODO */
1629 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001630
Harald Weltebed35df2011-11-02 13:06:18 +01001631 if (options.gtpversion == 0) {
1632 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001633 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001634 "QoS length too big");
1635 exit(1);
1636 } else {
1637 memcpy(pdp->qos_req0, options.qos.v,
1638 options.qos.l);
1639 }
1640 }
jjakoa7cd2492003-04-11 09:40:12 +00001641
Harald Weltebed35df2011-11-02 13:06:18 +01001642 pdp->qos_req.l = options.qos.l;
1643 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001644
Harald Weltebed35df2011-11-02 13:06:18 +01001645 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001646
Harald Weltebed35df2011-11-02 13:06:18 +01001647 pdp->rattype.l = options.rattype.l;
1648 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1649 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001650
Harald Weltebed35df2011-11-02 13:06:18 +01001651 pdp->userloc.l = options.userloc.l;
1652 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1653 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001654
Harald Weltebed35df2011-11-02 13:06:18 +01001655 pdp->rai.l = options.rai.l;
1656 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1657 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001658
Harald Weltebed35df2011-11-02 13:06:18 +01001659 pdp->mstz.l = options.mstz.l;
1660 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1661 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001662
Harald Weltebed35df2011-11-02 13:06:18 +01001663 pdp->imeisv.l = options.imeisv.l;
1664 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1665 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001666
Harald Weltebed35df2011-11-02 13:06:18 +01001667 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001668
Harald Weltebed35df2011-11-02 13:06:18 +01001669 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001670 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001671 "APN length too big");
1672 exit(1);
1673 } else {
1674 pdp->apn_use.l = options.apn.l;
1675 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1676 }
jjako193e8b12003-11-10 12:31:41 +00001677
Harald Weltebed35df2011-11-02 13:06:18 +01001678 pdp->gsnlc.l = sizeof(options.listen);
1679 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1680 pdp->gsnlu.l = sizeof(options.listen);
1681 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001682
Harald Weltebed35df2011-11-02 13:06:18 +01001683 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001684 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001685 "MSISDN length too big");
1686 exit(1);
1687 } else {
1688 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1689 }
jjakob62c3dd2004-05-27 18:51:55 +00001690
Harald Welte840a8e92017-09-24 18:12:40 +08001691 /* Request dynamic IP address */
1692 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1693 pdp->eua.v[1] = options.pdp_type;
1694 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001695
Harald Weltebed35df2011-11-02 13:06:18 +01001696 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001697 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001698 "PCO length too big");
1699 exit(1);
1700 } else {
1701 pdp->pco_req.l = options.pco.l;
1702 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1703 }
jjako52c24142002-12-16 13:33:51 +00001704
Harald Weltebed35df2011-11-02 13:06:18 +01001705 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001706
Harald Weltebed35df2011-11-02 13:06:18 +01001707 pdp->hisaddr0 = options.remote;
1708 pdp->hisaddr1 = options.remote;
1709
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01001710 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
Harald Weltebed35df2011-11-02 13:06:18 +01001711 512 = Flat rate, 256 = Hot billing */
1712
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001713 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1714
Harald Weltebed35df2011-11-02 13:06:18 +01001715 /* Create context */
1716 /* We send this of once. Retransmissions are handled by gtplib */
1717 gtp_create_context_req(gsn, pdp, &iparr[n]);
1718 }
1719
1720 state = 1; /* Enter wait_connection state */
1721
1722 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001723
jjako52c24142002-12-16 13:33:51 +00001724 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001725 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001726 /******************************************************************/
1727
Harald Weltebed35df2011-11-02 13:06:18 +01001728 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001729
Harald Weltebed35df2011-11-02 13:06:18 +01001730 /* Take down client after timeout after disconnect */
1731 if ((4 == state) && ((stoptime) <= time(NULL))) {
1732 state = 5;
1733 }
jjako7b8fad42003-07-07 14:37:42 +00001734
Harald Weltebed35df2011-11-02 13:06:18 +01001735 /* Take down client after timelimit timeout */
1736 if ((2 == state) && (options.timelimit) &&
1737 ((starttime + options.timelimit) <= time(NULL))) {
1738 state = 3;
1739 }
jjako7b8fad42003-07-07 14:37:42 +00001740
Harald Weltebed35df2011-11-02 13:06:18 +01001741 /* Take down client after ping timeout */
1742 if ((2 == state) && (pingtimeout)
1743 && (pingtimeout <= time(NULL))) {
1744 state = 3;
1745 }
jjako7b8fad42003-07-07 14:37:42 +00001746
Harald Weltebed35df2011-11-02 13:06:18 +01001747 /* Set pingtimeout for later disconnection */
1748 if (options.pingcount && ntransmitted >= options.pingcount) {
1749 pingtimeout = time(NULL) + 5; /* Extra seconds */
1750 }
jjako7b8fad42003-07-07 14:37:42 +00001751
Harald Weltebed35df2011-11-02 13:06:18 +01001752 /* Print statistics if no more ping packets are missing */
1753 if (ntransmitted && options.pingcount
1754 && nreceived >= options.pingcount) {
1755 ping_finish();
1756 if (!options.createif)
1757 state = 3;
1758 }
jjako7b8fad42003-07-07 14:37:42 +00001759
Harald Weltebed35df2011-11-02 13:06:18 +01001760 /* Send off disconnect */
1761 if (3 == state) {
1762 state = 4;
1763 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1764 for (n = 0; n < options.contexts; n++) {
1765 /* Delete context */
1766 printf("Disconnecting PDP context #%d\n", n);
Oliver Smith1cde2c12019-05-13 11:35:03 +02001767 gtp_delete_context_req2(gsn, iparr[n].pdp, NULL, 1);
Harald Weltebed35df2011-11-02 13:06:18 +01001768 if ((options.pinghost.s_addr != 0)
1769 && ntransmitted)
1770 ping_finish();
1771 }
1772 }
jjako7b8fad42003-07-07 14:37:42 +00001773
Harald Weltebed35df2011-11-02 13:06:18 +01001774 /* Send of ping packets */
1775 diff = 0;
1776 while ((diff <= 0) &&
1777 /* Send off an ICMP ping packet */
1778 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1779 ((pingseq < options.pingcount)
1780 || (options.pingcount == 0))) {
1781 if (!pingseq)
1782 gettimeofday(&firstping, &tz); /* Set time of first ping */
1783 gettimeofday(&tv, &tz);
1784 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1785 if (diff <= 0) {
1786 if (options.debug)
1787 printf("Create_ping %d\n", diff);
1788 create_ping(gsn,
1789 iparr[pingseq %
1790 options.contexts].pdp,
1791 &options.pinghost, pingseq,
1792 options.pingsize);
1793 pingseq++;
1794 }
1795 }
jjako5da68452003-01-28 16:08:47 +00001796
Harald Weltebed35df2011-11-02 13:06:18 +01001797 FD_ZERO(&fds);
1798 if (tun)
1799 FD_SET(tun->fd, &fds);
1800 FD_SET(gsn->fd0, &fds);
1801 FD_SET(gsn->fd1c, &fds);
1802 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001803
Harald Weltebed35df2011-11-02 13:06:18 +01001804 gtp_retranstimeout(gsn, &idleTime);
1805 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001806
Harald Weltebed35df2011-11-02 13:06:18 +01001807 if (options.debug)
1808 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1809 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001810
bjovana8f71eb2017-02-24 17:39:20 +01001811 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001812 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1813 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001814 if (errno == EINTR)
1815 signal_received = 1;
1816 else
1817 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1818 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001819 break;
1820 case 0:
1821 gtp_retrans(gsn); /* Only retransmit if nothing else */
1822 break;
1823 default:
1824 break;
1825 }
1826
bjovana8f71eb2017-02-24 17:39:20 +01001827 if (!signal_received) {
1828
1829 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1830 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1831 "TUN decaps failed");
1832 }
1833
1834 if (FD_ISSET(gsn->fd0, &fds))
1835 gtp_decaps0(gsn);
1836
1837 if (FD_ISSET(gsn->fd1c, &fds))
1838 gtp_decaps1c(gsn);
1839
1840 if (FD_ISSET(gsn->fd1u, &fds))
1841 gtp_decaps1u(gsn);
1842
Harald Weltebed35df2011-11-02 13:06:18 +01001843 }
Harald Weltebed35df2011-11-02 13:06:18 +01001844 }
1845
1846 gtp_free(gsn); /* Clean up the gsn instance */
1847
1848 if (options.createif)
1849 tun_free(tun);
1850
1851 if (0 == state)
1852 exit(1); /* Indicate error */
1853
1854 return 0;
jjako52c24142002-12-16 13:33:51 +00001855}