blob: bb55b1c8923a1913f9819569e87db7857260bd60 [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>
23
jjako52c24142002-12-16 13:33:51 +000024#include <ctype.h>
25#include <netdb.h>
26#include <signal.h>
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <netinet/in.h>
Harald Welte63ebccd2017-08-02 21:10:09 +020033#include <netinet/ip.h>
Harald Welte6748dc92017-09-24 21:54:59 +080034#include <netinet/ip6.h>
jjako52c24142002-12-16 13:33:51 +000035#include <arpa/inet.h>
36#include <sys/wait.h>
37#include <sys/stat.h>
38#include <unistd.h>
39#include <sys/socket.h>
40#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000041#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000042#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000043#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000044#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000045#include <resolv.h>
46#include <time.h>
47
jjakoff9985c2004-01-16 11:05:22 +000048#include "config.h"
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020049#include "../lib/tun.h"
50#include "../lib/ippool.h"
51#include "../lib/syserr.h"
jjako52c24142002-12-16 13:33:51 +000052#include "../gtp/pdp.h"
53#include "../gtp/gtp.h"
54#include "cmdline.h"
55
Harald Weltebed35df2011-11-02 13:06:18 +010056#define IPADDRLEN 256 /* Character length of addresses */
57#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000058
jjakoa7cd2492003-04-11 09:40:12 +000059/* HASH tables for IP address allocation */
60struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010061 uint8_t inuse; /* 0=free. 1=used by somebody */
62 struct iphash_t *ipnext;
63 struct pdp_t *pdp;
Harald Welted12eab92017-08-02 19:49:47 +020064 struct in46_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000065};
66struct iphash_t iparr[MAXCONTEXTS];
67struct iphash_t *iphash[MAXCONTEXTS];
68
69/* State variable used for ping */
70/* 0: Idle */
71/* 1: Wait_connect */
72/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000073/* 3: Done */
74/* 4: Wait_disconnect */
75/* 5: Disconnected */
bjovana8f71eb2017-02-24 17:39:20 +010076volatile sig_atomic_t state = 0;
jjako52c24142002-12-16 13:33:51 +000077
Harald Weltebed35df2011-11-02 13:06:18 +010078struct gsn_t *gsn = NULL; /* GSN instance */
79struct tun_t *tun = NULL; /* TUN instance */
80int maxfd = 0; /* For select() */
81int echoversion = 1; /* First try this version */
jjako52c24142002-12-16 13:33:51 +000082
jjakoa7cd2492003-04-11 09:40:12 +000083/* Struct with local versions of gengetopt options */
84struct {
Harald Weltebed35df2011-11-02 13:06:18 +010085 int debug; /* Print debug messages */
86 int createif; /* Create local network interface */
Harald Welte73abc382017-10-10 08:50:11 +080087 char *tun_dev_name;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +010088 struct in46_addr netaddr, destaddr, net; /* Network interface */
Harald Welted12eab92017-08-02 19:49:47 +020089 size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +010090 char *ipup, *ipdown; /* Filename of scripts */
91 int defaultroute; /* Set up default route */
92 struct in_addr pinghost; /* Remote ping host */
93 int pingrate;
94 int pingsize;
95 int pingcount;
96 int pingquiet;
97 struct in_addr listen;
98 struct in_addr remote;
99 struct in_addr dns;
100 int contexts; /* Number of contexts to create */
101 int timelimit; /* Number of seconds to be connected */
102 char *statedir;
103 uint64_t imsi;
104 uint8_t nsapi;
105 int gtpversion;
106 struct ul255_t pco;
107 struct ul255_t qos;
108 uint16_t cch;
109 struct ul255_t apn;
110 uint8_t selmode;
111 struct ul255_t rattype;
112 int rattype_given;
113 struct ul255_t userloc;
114 int userloc_given;
115 struct ul255_t rai;
116 int rai_given;
117 struct ul255_t mstz;
118 int mstz_given;
119 struct ul255_t imeisv;
120 int imeisv_given;
121 struct ul16_t msisdn;
122 int norecovery_given;
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800123 int tx_gpdu_seq;
Harald Welte840a8e92017-09-24 18:12:40 +0800124 uint8_t pdp_type;
jjakoa7cd2492003-04-11 09:40:12 +0000125} options;
jjako52c24142002-12-16 13:33:51 +0000126
jjako5da68452003-01-28 16:08:47 +0000127/* Definitions to use for PING. Most of the ping code was derived from */
128/* the original ping program by Mike Muuss */
129
130/* IP header and ICMP echo header */
131#define CREATEPING_MAX 2048
132#define CREATEPING_IP 20
133#define CREATEPING_ICMP 8
134
135struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100136 uint8_t ipver; /* Type and header length */
137 uint8_t tos; /* Type of Service */
138 uint16_t length; /* Total length */
139 uint16_t fragid; /* Identifier */
140 uint16_t offset; /* Flags and fragment offset */
141 uint8_t ttl; /* Time to live */
142 uint8_t protocol; /* Protocol */
143 uint16_t ipcheck; /* Header checksum */
144 uint32_t src; /* Source address */
145 uint32_t dst; /* Destination */
146 uint8_t type; /* Type and header length */
147 uint8_t code; /* Code */
148 uint16_t checksum; /* Header checksum */
149 uint16_t ident; /* Identifier */
150 uint16_t seq; /* Sequence number */
151 uint8_t data[CREATEPING_MAX]; /* Data */
152} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000153
154/* Statistical values for ping */
155int nreceived = 0;
156int ntreceived = 0;
157int ntransmitted = 0;
158int tmin = 999999999;
159int tmax = 0;
160int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100161int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000162struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000163
Harald Weltefed33892017-10-10 09:02:45 +0800164static void signal_handler(int signo)
bjovana8f71eb2017-02-24 17:39:20 +0100165{
166 if (state == 2)
167 state = 3; /* Tell main loop to finish. */
168}
169
Harald Weltefed33892017-10-10 09:02:45 +0800170static int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100171{
Harald Welted12eab92017-08-02 19:49:47 +0200172 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100173 struct iphash_t *h;
174 struct iphash_t *prev = NULL;
175 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200176 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100177 for (h = iphash[hash]; h; h = h->ipnext)
178 prev = h;
179 if (!prev)
180 iphash[hash] = ipaddr;
181 else
182 prev->ipnext = ipaddr;
183 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000184}
185
Harald Weltefed33892017-10-10 09:02:45 +0800186static int ipdel(struct iphash_t *ipaddr)
Harald Weltebed35df2011-11-02 13:06:18 +0100187{
Harald Welted12eab92017-08-02 19:49:47 +0200188 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100189 struct iphash_t *h;
190 struct iphash_t *prev = NULL;
191 for (h = iphash[hash]; h; h = h->ipnext) {
192 if (h == ipaddr) {
193 if (!prev)
194 iphash[hash] = h->ipnext;
195 else
196 prev->ipnext = h->ipnext;
197 return 0;
198 }
199 prev = h;
200 }
201 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000202}
203
Harald Weltefed33892017-10-10 09:02:45 +0800204static int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100205{
Harald Welted12eab92017-08-02 19:49:47 +0200206 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100207 struct iphash_t *h;
208 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200209 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100210 *ipaddr = h;
211 return 0;
212 }
213 }
214 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000215}
216
jjakoa7cd2492003-04-11 09:40:12 +0000217/* Used to write process ID to file. Assume someone else will delete */
Harald Weltefed33892017-10-10 09:02:45 +0800218static void log_pid(char *pidfile)
Harald Weltebed35df2011-11-02 13:06:18 +0100219{
220 FILE *file;
221 mode_t oldmask;
222
223 oldmask = umask(022);
224 file = fopen(pidfile, "w");
225 umask(oldmask);
226 if (!file)
227 return;
228 fprintf(file, "%d\n", (int)getpid());
229 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000230}
231
Harald Weltefed33892017-10-10 09:02:45 +0800232static int process_options(int argc, char **argv)
Harald Weltebed35df2011-11-02 13:06:18 +0100233{
234 /* gengeopt declarations */
235 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000236
Harald Weltebed35df2011-11-02 13:06:18 +0100237 struct hostent *host;
238 unsigned int n;
239 uint16_t i;
240 uint8_t a;
241 uint8_t b;
242 char *tmp;
243 char *pch;
244 char *type;
245 char *mcc;
246 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100247 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100248 char *lac;
249 int lac_d;
250 char *rest;
251 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
252 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
253 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
254 int sign;
255 int nbquarters;
256 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000257
Harald Weltebed35df2011-11-02 13:06:18 +0100258 if (cmdline_parser(argc, argv, &args_info) != 0)
259 return -1;
260 if (args_info.debug_flag) {
261 if (args_info.remote_arg)
262 printf("remote: %s\n", args_info.remote_arg);
263 if (args_info.listen_arg)
264 printf("listen: %s\n", args_info.listen_arg);
265 if (args_info.conf_arg)
266 printf("conf: %s\n", args_info.conf_arg);
267 printf("debug: %d\n", args_info.debug_flag);
268 if (args_info.imsi_arg)
269 printf("imsi: %s\n", args_info.imsi_arg);
270 printf("qos: %#08x\n", args_info.qos_arg);
271 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
272 printf("qose2: %#04x\n", args_info.qose2_arg);
273 printf("qose3: %#06x\n", args_info.qose3_arg);
274 printf("qose4: %#06x\n", args_info.qose4_arg);
275 printf("charging: %#04x\n", args_info.charging_arg);
276 if (args_info.apn_arg)
277 printf("apn: %s\n", args_info.apn_arg);
278 if (args_info.msisdn_arg)
279 printf("msisdn: %s\n", args_info.msisdn_arg);
280 if (args_info.uid_arg)
281 printf("uid: %s\n", args_info.uid_arg);
282 if (args_info.pwd_arg)
283 printf("pwd: %s\n", args_info.pwd_arg);
284 if (args_info.pidfile_arg)
285 printf("pidfile: %s\n", args_info.pidfile_arg);
286 if (args_info.statedir_arg)
287 printf("statedir: %s\n", args_info.statedir_arg);
288 if (args_info.dns_arg)
289 printf("dns: %s\n", args_info.dns_arg);
290 printf("contexts: %d\n", args_info.contexts_arg);
291 printf("timelimit: %d\n", args_info.timelimit_arg);
292 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800293 if (args_info.tun_device_arg)
294 printf("tun-device: %d\n", args_info.tun_device_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100295 if (args_info.ipup_arg)
296 printf("ipup: %s\n", args_info.ipup_arg);
297 if (args_info.ipdown_arg)
298 printf("ipdown: %s\n", args_info.ipdown_arg);
299 printf("defaultroute: %d\n", args_info.defaultroute_flag);
300 if (args_info.pinghost_arg)
301 printf("pinghost: %s\n", args_info.pinghost_arg);
302 printf("pingrate: %d\n", args_info.pingrate_arg);
303 printf("pingsize: %d\n", args_info.pingsize_arg);
304 printf("pingcount: %d\n", args_info.pingcount_arg);
305 printf("pingquiet: %d\n", args_info.pingquiet_flag);
306 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800307 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100308 }
jjakoa7cd2492003-04-11 09:40:12 +0000309
Harald Weltebed35df2011-11-02 13:06:18 +0100310 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000311
Harald Weltebed35df2011-11-02 13:06:18 +0100312 if (args_info.conf_arg) {
313 if (cmdline_parser_configfile
314 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
315 return -1;
316 if (args_info.debug_flag) {
317 printf("cmdline_parser_configfile\n");
318 if (args_info.remote_arg)
319 printf("remote: %s\n", args_info.remote_arg);
320 if (args_info.listen_arg)
321 printf("listen: %s\n", args_info.listen_arg);
322 if (args_info.conf_arg)
323 printf("conf: %s\n", args_info.conf_arg);
324 printf("debug: %d\n", args_info.debug_flag);
325 if (args_info.imsi_arg)
326 printf("imsi: %s\n", args_info.imsi_arg);
327 printf("qos: %#08x\n", args_info.qos_arg);
328 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
329 printf("qose2: %#04x\n", args_info.qose2_arg);
330 printf("qose3: %#06x\n", args_info.qose3_arg);
331 printf("qose4: %#06x\n", args_info.qose4_arg);
332 printf("charging: %#04x\n", args_info.charging_arg);
333 if (args_info.apn_arg)
334 printf("apn: %s\n", args_info.apn_arg);
335 if (args_info.msisdn_arg)
336 printf("msisdn: %s\n", args_info.msisdn_arg);
337 if (args_info.uid_arg)
338 printf("uid: %s\n", args_info.uid_arg);
339 if (args_info.pwd_arg)
340 printf("pwd: %s\n", args_info.pwd_arg);
341 if (args_info.pidfile_arg)
342 printf("pidfile: %s\n", args_info.pidfile_arg);
343 if (args_info.statedir_arg)
344 printf("statedir: %s\n",
345 args_info.statedir_arg);
346 if (args_info.dns_arg)
347 printf("dns: %s\n", args_info.dns_arg);
348 printf("contexts: %d\n", args_info.contexts_arg);
349 printf("timelimit: %d\n", args_info.timelimit_arg);
350 printf("createif: %d\n", args_info.createif_flag);
Harald Welte73abc382017-10-10 08:50:11 +0800351 if (args_info.tun_device_arg)
Harald Welte9c332102017-11-06 02:44:42 +0900352 printf("tun-device: %s\n", args_info.tun_device_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100353 if (args_info.ipup_arg)
354 printf("ipup: %s\n", args_info.ipup_arg);
355 if (args_info.ipdown_arg)
356 printf("ipdown: %s\n", args_info.ipdown_arg);
357 printf("defaultroute: %d\n",
358 args_info.defaultroute_flag);
359 if (args_info.pinghost_arg)
360 printf("pinghost: %s\n",
361 args_info.pinghost_arg);
362 printf("pingrate: %d\n", args_info.pingrate_arg);
363 printf("pingsize: %d\n", args_info.pingsize_arg);
364 printf("pingcount: %d\n", args_info.pingcount_arg);
365 printf("pingquiet: %d\n", args_info.pingquiet_flag);
366 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800367 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100368 }
369 }
jjako193e8b12003-11-10 12:31:41 +0000370
Harald Weltebed35df2011-11-02 13:06:18 +0100371 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000372
Harald Weltebed35df2011-11-02 13:06:18 +0100373 /* foreground */
374 /* If fg flag not given run as a daemon */
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100375 /* Do not allow sgsnemu to run as deamon
Harald Weltebed35df2011-11-02 13:06:18 +0100376 if (!args_info.fg_flag)
377 {
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +0100378 closelog();
Harald Weltebed35df2011-11-02 13:06:18 +0100379 freopen("/dev/null", "w", stdout);
380 freopen("/dev/null", "w", stderr);
381 freopen("/dev/null", "r", stdin);
382 daemon(0, 0);
383 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
384 } */
jjako1a51df72004-07-20 08:30:21 +0000385
Harald Weltebed35df2011-11-02 13:06:18 +0100386 /* debug */
387 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000388
Harald Weltebed35df2011-11-02 13:06:18 +0100389 /* pidfile */
390 /* This has to be done after we have our final pid */
391 if (args_info.pidfile_arg) {
392 log_pid(args_info.pidfile_arg);
393 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200394
Harald Weltebed35df2011-11-02 13:06:18 +0100395 /* dns */
396 /* If no dns option is given use system default */
397 /* Do hostname lookup to translate hostname to IP address */
398 printf("\n");
399 if (args_info.dns_arg) {
400 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100401 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100402 "Invalid DNS address: %s!", args_info.dns_arg);
403 return -1;
404 } else {
405 memcpy(&options.dns.s_addr, host->h_addr,
406 host->h_length);
407 _res.nscount = 1;
408 _res.nsaddr_list[0].sin_addr = options.dns;
409 printf("Using DNS server: %s (%s)\n",
410 args_info.dns_arg, inet_ntoa(options.dns));
411 }
412 } else {
413 options.dns.s_addr = 0;
414 printf("Using default DNS server\n");
415 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200416
Harald Weltebed35df2011-11-02 13:06:18 +0100417 /* listen */
418 /* If no listen option is specified listen to any local port */
419 /* Do hostname lookup to translate hostname to IP address */
420 if (args_info.listen_arg) {
421 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100422 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100423 "Invalid listening address: %s!",
424 args_info.listen_arg);
425 return -1;
426 } else {
427 memcpy(&options.listen.s_addr, host->h_addr,
428 host->h_length);
429 printf("Local IP address is: %s (%s)\n",
430 args_info.listen_arg, inet_ntoa(options.listen));
431 }
432 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100433 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100434 "Listening address must be specified: %s!",
435 args_info.listen_arg);
436 return -1;
437 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200438
Harald Weltebed35df2011-11-02 13:06:18 +0100439 /* remote */
440 /* If no remote option is specified terminate */
441 /* Do hostname lookup to translate hostname to IP address */
442 if (args_info.remote_arg) {
443 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100444 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100445 "Invalid remote address: %s!",
446 args_info.remote_arg);
447 return -1;
448 } else {
449 memcpy(&options.remote.s_addr, host->h_addr,
450 host->h_length);
451 printf("Remote IP address is: %s (%s)\n",
452 args_info.remote_arg, inet_ntoa(options.remote));
453 }
454 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100455 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100456 "No remote address given!");
457 return -1;
458 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200459
Harald Weltebed35df2011-11-02 13:06:18 +0100460 /* imsi */
461 if (strlen(args_info.imsi_arg) != 15) {
462 printf("Invalid IMSI\n");
463 return -1;
464 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200465
Harald Weltebed35df2011-11-02 13:06:18 +0100466 options.imsi = 0xf000000000000000ull;
467 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
468 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
469 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
470 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
471 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
472 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
473 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
474 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
475 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
476 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
477 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
478 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
479 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
480 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
481 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200482
Harald Weltebed35df2011-11-02 13:06:18 +0100483 printf("IMSI is: %s (%#08llx)\n",
484 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200485
Harald Weltebed35df2011-11-02 13:06:18 +0100486 /* nsapi */
487 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
488 printf("Invalid NSAPI\n");
489 return -1;
490 }
491 options.nsapi = args_info.nsapi_arg;
492 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200493
Harald Weltebed35df2011-11-02 13:06:18 +0100494 /* qos */
495 options.qos.l = 4;
496 options.qos.v[3] = (args_info.qos_arg) & 0xff;
497 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
498 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
499 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
500 /* Extensions according to 3GPP TS 24.008 */
501 if (args_info.qose1_given == 1) {
502 options.qos.l = 12;
503 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
504 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
505 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
506 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
507 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
508 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
509 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
510 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
511 if (args_info.qose2_given == 1) {
512 options.qos.l = 13;
513 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
514 if (args_info.qose3_given == 1) {
515 options.qos.l = 15;
516 options.qos.v[14] =
517 (args_info.qose3_arg) & 0xff;
518 options.qos.v[13] =
519 ((args_info.qose3_arg) >> 8) & 0xff;
520 if (args_info.qose4_given == 1) {
521 options.qos.l = 17;
522 options.qos.v[16] =
523 (args_info.qose4_arg) & 0xff;
524 options.qos.v[15] =
525 ((args_info.qose4_arg) >> 8) & 0xff;
526 }
527 }
528 }
529 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200530
Harald Weltebed35df2011-11-02 13:06:18 +0100531 /* charging */
532 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200533
Harald Weltebed35df2011-11-02 13:06:18 +0100534 /* contexts */
535 if (args_info.contexts_arg > MAXCONTEXTS) {
536 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
537 return -1;
538 }
539 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200540
Harald Weltebed35df2011-11-02 13:06:18 +0100541 /* Timelimit */
542 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200543
Harald Weltebed35df2011-11-02 13:06:18 +0100544 /* gtpversion */
545 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
546 printf("Invalid GTP version\n");
547 return -1;
548 }
549 options.gtpversion = args_info.gtpversion_arg;
550 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200551
Harald Weltebed35df2011-11-02 13:06:18 +0100552 /* apn */
553 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
554 printf("Invalid APN\n");
555 return -1;
556 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100557 options.apn.l = strlen(args_info.apn_arg) + 1;
558
559 apn = (char *)options.apn.v;
560 for (tok = strtok(args_info.apn_arg, ".");
561 tok != NULL;
562 tok = strtok(NULL, ".")) {
563 size_t len = strlen(tok);
564
565 *apn++ = (char)len;
566 strncpy(apn, tok, len);
567 apn += len;
568 }
569
Harald Weltebed35df2011-11-02 13:06:18 +0100570 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200571
Harald Weltebed35df2011-11-02 13:06:18 +0100572 /* selmode */
573 options.selmode = args_info.selmode_arg;
574 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200575
Harald Weltebed35df2011-11-02 13:06:18 +0100576 /* rattype */
577 if (args_info.rattype_given == 1) {
578 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800579 options.rattype.l = 1;
580 options.rattype.v[0] = args_info.rattype_arg;
581 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100582 }
Harald Welte41af5692011-10-07 18:42:34 +0200583
Harald Weltebed35df2011-11-02 13:06:18 +0100584 /* userloc */
585 if (args_info.userloc_given == 1) {
586 printf("Using User Location Information: %s\n",
587 args_info.userloc_arg);
588 tmp = args_info.userloc_arg;
589 n = 0;
590 pch = strtok(tmp, ".");
591 while (pch != NULL) {
592 userloc_el[n] = pch;
593 pch = strtok(NULL, ".");
594 n++;
595 }
Harald Welte41af5692011-10-07 18:42:34 +0200596
Harald Weltebed35df2011-11-02 13:06:18 +0100597 options.userloc_given = 1;
598 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200599
Harald Weltebed35df2011-11-02 13:06:18 +0100600 /* 3GPP Geographic Location Type t0 / t1 / t2 */
601 type = userloc_el[0];
602 printf("->type : %c\n", type[0]);
603 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
604 printf("Invalid type \n");
605 return -1;
606 }
607 /* options.userloc.v[0] = 0x00 */
608 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200609
Harald Weltebed35df2011-11-02 13:06:18 +0100610 /* MCC */
611 mcc = userloc_el[1];
612 printf("->mcc : %s\n", mcc);
613 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200614 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100615 return -1;
616 }
Harald Welte41af5692011-10-07 18:42:34 +0200617
Harald Weltebed35df2011-11-02 13:06:18 +0100618 /* MNC */
619 mnc = userloc_el[2];
620 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200621
Harald Weltebed35df2011-11-02 13:06:18 +0100622 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
623 /* options.userloc.v[1] = 0x52 */
624 a = (uint8_t) (mcc[0] - 48);
625 b = (uint8_t) (mcc[1] - 48);
626 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200627
Harald Weltebed35df2011-11-02 13:06:18 +0100628 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
629 /* options.userloc.v[2] = 0xf0 */
630 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200631
Harald Weltebed35df2011-11-02 13:06:18 +0100632 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200633 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100634 return -1;
635 }
636 if (strlen(mnc) == 2) {
637 b = 15;
638 }
639 if (strlen(mnc) == 3) {
640 b = (uint8_t) (mnc[2] - 48);
641 }
642 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200643
Harald Weltebed35df2011-11-02 13:06:18 +0100644 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
645 /* options.userloc.v[3] = 0x99 */
646 a = (uint8_t) (mnc[0] - 48);
647 b = (uint8_t) (mnc[1] - 48);
648 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200649
Harald Weltebed35df2011-11-02 13:06:18 +0100650 /* LAC */
651 lac = userloc_el[3];
652 /*options.userloc.v[4] = 0x12 ; */
653 /*options.userloc.v[5] = 0x10 ; */
654 printf("->LAC: %s\n", lac);
655 lac_d = atoi(lac);
656 if (lac_d > 65535 || lac_d < 1) {
657 printf("Invalid LAC\n");
658 return -1;
659 }
660 i = lac_d >> 8;
661 options.userloc.v[4] = i; /* octet 8 - LAC */
662 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200663
Harald Weltebed35df2011-11-02 13:06:18 +0100664 /* CI/SAC/RAC */
665 rest = userloc_el[4];
666 printf("->CI/SAC/RAC : %s\n", rest);
667 lac_d = atoi(rest);
668 if (lac_d > 65535 || lac_d < 1) {
669 printf("Invalid CI/SAC/RAC\n");
670 return -1;
671 }
672 /*options.userloc.v[6] = 0x04 ; */
673 /*options.userloc.v[7] = 0xb7 ; */
674 i = lac_d >> 8;
675 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
676 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
677 }
jjakoa7cd2492003-04-11 09:40:12 +0000678
Harald Weltebed35df2011-11-02 13:06:18 +0100679 /* RAI */
680 if (args_info.rai_given == 1) {
681 printf("Using RAI: %s\n", args_info.rai_arg);
682 tmp = args_info.rai_arg;
683 n = 0;
684 pch = strtok(tmp, ".");
685 while (pch != NULL) {
686 rai_el[n] = pch;
687 pch = strtok(NULL, ".");
688 n++;
689 }
jjakoa7cd2492003-04-11 09:40:12 +0000690
Harald Weltebed35df2011-11-02 13:06:18 +0100691 options.rai_given = 1;
692 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000693
Harald Weltebed35df2011-11-02 13:06:18 +0100694 /* MCC */
695 mcc = rai_el[0];
696 printf("->mcc : %s\n", mcc);
697 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200698 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100699 return -1;
700 }
701
702 /* MNC */
703 mnc = rai_el[1];
704 printf("->mnc : %s\n", mnc);
705
706 a = (uint8_t) (mcc[0] - 48);
707 b = (uint8_t) (mcc[1] - 48);
708 options.rai.v[0] = 16 * b + a;
709
710 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
711 a = (uint8_t) (mcc[2] - 48);
712
713 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200714 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100715 return -1;
716 }
717 if (strlen(mnc) == 2) {
718 b = 15;
719 }
720 if (strlen(mnc) == 3) {
721 b = (uint8_t) (mnc[2] - 48);
722 }
723 options.rai.v[1] = 16 * b + a;
724
725 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
726 a = (uint8_t) (mnc[0] - 48);
727 b = (uint8_t) (mnc[1] - 48);
728 options.rai.v[2] = 16 * b + a;
729
730 /* LAC */
731 lac = rai_el[2];
732 printf("->LAC: %s\n", lac);
733 lac_d = atoi(lac);
734 if (lac_d > 65535 || lac_d < 1) {
735 printf("Invalid LAC\n");
736 return -1;
737 }
738 i = lac_d >> 8;
739 options.rai.v[3] = i; /* octet 5 - LAC */
740 options.rai.v[4] = lac_d; /* octet 6 - LAC */
741
742 /* RAC */
743 rest = rai_el[3];
744 printf("->RAC : %s\n", rest);
745 lac_d = atoi(rest);
746 if (lac_d > 255 || lac_d < 1) {
747 printf("Invalid RAC\n");
748 return -1;
749 }
750 options.rai.v[5] = lac_d; /* octet 7 - RAC */
751 }
752
753 /* mstz */
754 if (args_info.mstz_given == 1) {
755 options.mstz_given = 1;
756 options.mstz.l = 2;
757
758 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
759 tmp = args_info.mstz_arg;
760 n = 0;
761 pch = strtok(tmp, ".");
762 while (pch != NULL) {
763 mstz_el[n] = pch;
764 pch = strtok(NULL, ".");
765 n++;
766 }
767
768 /* sign */
769 sign = atoi(mstz_el[0]);
770 printf("->Sign (0=+ / 1=-): %d\n", sign);
771 if (sign != 0 && sign != 1) {
772 printf("Invalid Sign \n");
773 return -1;
774 }
775 /* nbquarters */
776 nbquarters = atoi(mstz_el[1]);
777 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
778 if (nbquarters < 0 || nbquarters > 79) {
779 printf("Invalid Number of Quarters \n");
780 return -1;
781 }
782 /* DST */
783 DST = atoi(mstz_el[2]);
784 printf("->Daylight Saving Time Adjustment : %d\n", DST);
785 if (DST < 0 || DST > 3) {
786 printf("Invalid DST Adjustment \n");
787 return -1;
788 }
789 /* 12345678
790 bits 123 = unit of # of quarters of an hour
791 bits 678 = # of quarters of an hour / 10
792 bit 5 = sign
793 */
794 i = nbquarters % 10;
795 i = i << 4;
796 i = i + nbquarters / 10 + 8 * sign;
797 /* options.mstz.v[0] = 0x69 ; */
798 /* options.mstz.v[1] = 0x01 ; */
799 options.mstz.v[0] = i;
800 options.mstz.v[1] = DST;
801 n = (i & 0x08) ? '-' : '+';
802 printf
803 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
804 n, nbquarters / 4, nbquarters % 4 * 15);
805 }
806
807 /* imeisv */
808 if (args_info.imeisv_given == 1) {
809 options.imeisv_given = 1;
810 if (strlen(args_info.imeisv_arg) != 16) {
811 printf("Invalid IMEI(SV)\n");
812 return -1;
813 }
814 options.imeisv.l = 8;
815 for (n = 0; n < 8; n++) {
816 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
817 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
818 options.imeisv.v[n] = 16 * b + a;
819 }
820 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
821 }
822
823 /* msisdn */
824 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
825 printf("Invalid MSISDN\n");
826 return -1;
827 }
828 options.msisdn.l = 1;
829 options.msisdn.v[0] = 0x91; /* International format */
830 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
831 if ((n % 2) == 0) {
832 options.msisdn.v[((int)n / 2) + 1] =
833 args_info.msisdn_arg[n] - 48 + 0xf0;
834 options.msisdn.l += 1;
835 } else {
836 options.msisdn.v[((int)n / 2) + 1] =
837 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
838 (args_info.msisdn_arg[n] - 48) * 16;
839 }
840 }
841 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
842
843 /* UID and PWD */
844 /* Might need to also insert stuff like DNS etc. */
845 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
846 (sizeof(options.pco.v) - 1)) {
847 printf("invalid UID and PWD\n");
848 return -1;
849 }
850 options.pco.l =
851 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
852 options.pco.v[0] = 0x80; /* PPP */
853 options.pco.v[1] = 0xc0; /* PAP */
854 options.pco.v[2] = 0x23;
855 options.pco.v[3] =
856 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
857 options.pco.v[4] = 0x01; /* Authenticate request */
858 options.pco.v[5] = 0x01;
859 options.pco.v[6] = 0x00; /* MSB of length */
860 options.pco.v[7] =
861 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
862 options.pco.v[8] = strlen(args_info.uid_arg);
863 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
864 options.pco.v[9 + strlen(args_info.uid_arg)] =
865 strlen(args_info.pwd_arg);
866 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
867 args_info.pwd_arg, strlen(args_info.pwd_arg));
868
869 /* createif */
870 options.createif = args_info.createif_flag;
Harald Welte73abc382017-10-10 08:50:11 +0800871 options.tun_dev_name = args_info.tun_device_arg;
Harald Weltebed35df2011-11-02 13:06:18 +0100872
873 /* net */
874 /* Store net as in_addr net and mask */
875 if (args_info.net_arg) {
876 if (ippool_aton
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100877 (&options.net, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100878 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100879 "Invalid network address: %s!",
880 args_info.net_arg);
881 exit(1);
882 }
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100883 options.netaddr = options.net;
884 options.destaddr = options.net;
jjakoc6762cf2004-04-28 14:52:58 +0000885
Harald Weltebed35df2011-11-02 13:06:18 +0100886 } else {
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100887 memset(&options.net, 0, sizeof(options.net));
Harald Welted12eab92017-08-02 19:49:47 +0200888 options.prefixlen = 0;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +0100889 memset(&options.netaddr, 0, sizeof(options.netaddr));
890 memset(&options.destaddr, 0, sizeof(options.destaddr));
Harald Weltebed35df2011-11-02 13:06:18 +0100891 }
jjako193e8b12003-11-10 12:31:41 +0000892
Harald Weltebed35df2011-11-02 13:06:18 +0100893 /* ipup */
894 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000895
Harald Weltebed35df2011-11-02 13:06:18 +0100896 /* ipdown */
897 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000898
Harald Weltebed35df2011-11-02 13:06:18 +0100899 /* statedir */
900 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000901
Harald Weltebed35df2011-11-02 13:06:18 +0100902 /* defaultroute */
903 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000904
Harald Weltebed35df2011-11-02 13:06:18 +0100905 /* pinghost */
906 /* Store ping host as in_addr */
907 if (args_info.pinghost_arg) {
908 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100909 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100910 "Invalid ping host: %s!",
911 args_info.pinghost_arg);
912 return -1;
913 } else {
914 memcpy(&options.pinghost.s_addr, host->h_addr,
915 host->h_length);
916 printf("Using ping host: %s (%s)\n",
917 args_info.pinghost_arg,
918 inet_ntoa(options.pinghost));
919 }
920 }
jjakoa7cd2492003-04-11 09:40:12 +0000921
Harald Weltebed35df2011-11-02 13:06:18 +0100922 /* Other ping parameters */
923 options.pingrate = args_info.pingrate_arg;
924 options.pingsize = args_info.pingsize_arg;
925 options.pingcount = args_info.pingcount_arg;
926 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000927
Harald Weltebed35df2011-11-02 13:06:18 +0100928 /* norecovery */
929 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000930
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800931 if (args_info.no_tx_gpdu_seq_flag)
932 options.tx_gpdu_seq = 0;
933 else
934 options.tx_gpdu_seq = 1;
935
Harald Welte840a8e92017-09-24 18:12:40 +0800936 /* PDP Type */
937 if (!strcmp(args_info.pdp_type_arg, "v6"))
938 options.pdp_type = PDP_EUA_TYPE_v6;
Harald Welte6748dc92017-09-24 21:54:59 +0800939 else if (!strcmp(args_info.pdp_type_arg, "v4"))
Harald Welte840a8e92017-09-24 18:12:40 +0800940 options.pdp_type = PDP_EUA_TYPE_v4;
Harald Welte6748dc92017-09-24 21:54:59 +0800941 else {
942 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
943 args_info.pdp_type_arg);
944 return -1;
945 }
946
947 if (options.pingcount && options.pdp_type != PDP_EUA_TYPE_v4) {
948 SYS_ERR(DSGSN, LOGL_ERROR, 0, "built-in ping only works with IPv4, use tun-device");
949 return -1;
950 }
Harald Welte840a8e92017-09-24 18:12:40 +0800951
Harald Weltebed35df2011-11-02 13:06:18 +0100952 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000953
954}
955
Harald Welte081f30c2017-10-10 09:36:35 +0800956/* read a single value from a /procc file, up to 255 bytes, callee-allocated */
957static char *proc_read(const char *path)
958{
959 char *ret = NULL;
960 FILE *f;
961
962 f = fopen(path, "r");
963 if (!f)
964 return NULL;
965
966 ret = malloc(256);
967 if (!ret)
968 goto out;
969
970 if (!fgets(ret, 256, f)) {
971 free(ret);
972 ret = NULL;
973 goto out;
974 }
Harald Welte081f30c2017-10-10 09:36:35 +0800975
976out:
977 fclose(f);
978 return ret;
979}
980
981/* Read value of a /proc/sys/net/ipv6/conf file for given device.
982 * Memory is dynamically allocated, caller must free it later. */
983static char *proc_ipv6_conf_read(const char *dev, const char *file)
984{
985 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
Harald Welteb11ed0f2017-11-06 03:07:26 +0900986 char path[strlen(fmt) + strlen(dev) + strlen(file)+1];
Harald Welte081f30c2017-10-10 09:36:35 +0800987 snprintf(path, sizeof(path), fmt, dev, file);
988 return proc_read(path);
989}
990
Harald Weltefed33892017-10-10 09:02:45 +0800991static char *print_ipprot(int t)
Harald Weltebed35df2011-11-02 13:06:18 +0100992{
Harald Weltee37f48e2017-10-10 09:05:50 +0800993 struct protoent *pe = getprotobynumber(t);
994
995 if (!pe)
Harald Weltebed35df2011-11-02 13:06:18 +0100996 return "Unknown";
Harald Weltee37f48e2017-10-10 09:05:50 +0800997 else
998 return pe->p_name;
jjako5da68452003-01-28 16:08:47 +0000999}
1000
Harald Weltefed33892017-10-10 09:02:45 +08001001static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001002{
1003 static char *ttab[] = {
1004 "Echo Reply",
1005 "ICMP 1",
1006 "ICMP 2",
1007 "Dest Unreachable",
1008 "Source Quench",
1009 "Redirect",
1010 "ICMP 6",
1011 "ICMP 7",
1012 "Echo",
1013 "ICMP 9",
1014 "ICMP 10",
1015 "Time Exceeded",
1016 "Parameter Problem",
1017 "Timestamp",
1018 "Timestamp Reply",
1019 "Info Request",
1020 "Info Reply"
1021 };
1022 if (t < 0 || t > 16)
1023 return ("OUT-OF-RANGE");
1024 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001025}
1026
Harald Weltefed33892017-10-10 09:02:45 +08001027static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001028{
1029 unsigned int n;
1030 uint64_t i64 = 0;
1031 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1032 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001033
Harald Weltebed35df2011-11-02 13:06:18 +01001034 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1035 /* ul16_t format always starts with 0x91 to indicate international format */
1036 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1037 for (n = 0; n < src->l; n++) {
1038 if ((src->v[n] & 0x0f) != 0x0f) {
1039 i64 *= 10;
1040 i64 += src->v[n] & 0x0f;
1041 }
1042 if ((src->v[n] & 0xf0) != 0xf0) {
1043 i64 *= 10;
1044 i64 += (src->v[n] & 0xf0) >> 4;
1045 }
1046 }
jjako193e8b12003-11-10 12:31:41 +00001047
Harald Weltebed35df2011-11-02 13:06:18 +01001048 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001049
Harald Weltebed35df2011-11-02 13:06:18 +01001050 /* Generate array with least significant digit in first octet */
1051 while (i64) {
1052 msa[msalen++] = i64 % 10;
1053 i64 = i64 / 10;
1054 }
jjako193e8b12003-11-10 12:31:41 +00001055
Harald Weltebed35df2011-11-02 13:06:18 +01001056 /* Convert back to ul16_t format */
1057 for (n = 0; n < msalen; n++) {
1058 if ((n % 2) == 0) {
1059 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1060 dst->l += 1;
1061 } else {
1062 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1063 msa[msalen - n - 1] * 16;
1064 }
1065 }
jjako193e8b12003-11-10 12:31:41 +00001066
Harald Weltebed35df2011-11-02 13:06:18 +01001067 return 0;
jjako193e8b12003-11-10 12:31:41 +00001068
1069}
1070
Harald Weltefed33892017-10-10 09:02:45 +08001071static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001072{
1073 /* TODO: big endian / small endian ??? */
1074 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001075
Harald Weltebed35df2011-11-02 13:06:18 +01001076 /* Convert from uint64_t bcd to uint64_t integer format */
1077 /* The resulting integer format is multiplied by 10 */
1078 while (src) {
1079 if ((src & 0x0f) != 0x0f) {
1080 i64 *= 10;
1081 i64 += (src & 0x0f);
1082 }
1083 if ((src & 0xf0) != 0xf0) {
1084 i64 *= 10;
1085 i64 += (src & 0xf0) >> 4;
1086 }
1087 src = src >> 8;
1088 }
jjako193e8b12003-11-10 12:31:41 +00001089
Harald Weltebed35df2011-11-02 13:06:18 +01001090 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001091
Harald Weltebed35df2011-11-02 13:06:18 +01001092 *dst = 0;
1093 while (i64) {
1094 *dst = *dst << 4;
1095 *dst += (i64 % 10);
1096 i64 = i64 / 10;
1097 }
jjako193e8b12003-11-10 12:31:41 +00001098
Harald Weltebed35df2011-11-02 13:06:18 +01001099 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001100
Harald Weltebed35df2011-11-02 13:06:18 +01001101 return 0;
jjako193e8b12003-11-10 12:31:41 +00001102
1103}
1104
jjakoafb2a972003-01-29 21:04:13 +00001105/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001106static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001107{
1108 struct timezone tz;
1109 struct timeval tv;
1110 int diff;
1111 if ((options.pinghost.s_addr) && (2 == state) &&
1112 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1113 gettimeofday(&tv, &tz);
1114 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1115 tp->tv_sec = 0;
1116 if (diff > 0)
1117 tp->tv_usec = diff;
1118 else {
1119 /* For some reason we get packet loss if set to zero */
1120 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1121 tp->tv_usec = 0;
1122 }
1123 }
1124 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001125}
1126
jjako5da68452003-01-28 16:08:47 +00001127/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001128static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001129{
Harald Weltebed35df2011-11-02 13:06:18 +01001130 struct timezone tz;
1131 struct timeval tv;
1132 int elapsed;
1133 gettimeofday(&tv, &tz);
1134 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1135 printf("\n");
1136 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1137 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1138 elapsed / 1000000.0);
1139 printf("%d packets received, ", nreceived);
1140 if (ntransmitted) {
1141 if (nreceived > ntransmitted)
1142 printf("-- somebody's printing up packets!");
1143 else
1144 printf("%d%% packet loss",
1145 (int)(((ntransmitted - nreceived) * 100) /
1146 ntransmitted));
1147 }
1148 printf("\n");
1149 if (options.debug)
1150 printf("%d packets received in total\n", ntreceived);
1151 if (nreceived && tsum)
1152 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1153 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1154 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001155
Harald Weltebed35df2011-11-02 13:06:18 +01001156 ntransmitted = 0;
1157 return 0;
jjako5da68452003-01-28 16:08:47 +00001158}
1159
1160/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltefed33892017-10-10 09:02:45 +08001161static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001162{
1163 struct timezone tz;
1164 struct timeval tv;
1165 struct timeval *tp;
1166 struct ip_ping *pingpack = pack;
1167 struct in_addr src;
1168 int triptime;
jjako5da68452003-01-28 16:08:47 +00001169
Harald Weltebed35df2011-11-02 13:06:18 +01001170 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001171
Harald Weltebed35df2011-11-02 13:06:18 +01001172 gettimeofday(&tv, &tz);
1173 if (options.debug)
1174 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001175
Harald Weltebed35df2011-11-02 13:06:18 +01001176 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1177 printf("packet too short (%d bytes) from %s\n", len,
1178 inet_ntoa(src));
1179 return 0;
1180 }
jjako5da68452003-01-28 16:08:47 +00001181
Harald Weltebed35df2011-11-02 13:06:18 +01001182 ntreceived++;
1183 if (pingpack->protocol != 1) {
1184 if (!options.pingquiet)
1185 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1186 len, inet_ntoa(src), pingpack->protocol,
1187 print_ipprot(pingpack->protocol));
1188 return 0;
1189 }
jjako5da68452003-01-28 16:08:47 +00001190
Harald Weltebed35df2011-11-02 13:06:18 +01001191 if (pingpack->type != 0) {
1192 if (!options.pingquiet)
1193 printf
1194 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1195 len, inet_ntoa(src), pingpack->type,
1196 print_icmptype(pingpack->type), pingpack->code);
1197 return 0;
1198 }
jjako5da68452003-01-28 16:08:47 +00001199
Harald Weltebed35df2011-11-02 13:06:18 +01001200 nreceived++;
1201 if (!options.pingquiet)
1202 printf("%d bytes from %s: icmp_seq=%d", len,
1203 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001204
Harald Weltebed35df2011-11-02 13:06:18 +01001205 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1206 gettimeofday(&tv, &tz);
1207 tp = (struct timeval *)pingpack->data;
1208 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1209 tv.tv_sec--;
1210 tv.tv_usec += 1000000;
1211 }
1212 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001213
Harald Weltebed35df2011-11-02 13:06:18 +01001214 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1215 tsum += triptime;
1216 if (triptime < tmin)
1217 tmin = triptime;
1218 if (triptime > tmax)
1219 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001220
Harald Weltebed35df2011-11-02 13:06:18 +01001221 if (!options.pingquiet)
1222 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001223
Harald Weltebed35df2011-11-02 13:06:18 +01001224 } else if (!options.pingquiet)
1225 printf("\n");
1226 return 0;
jjako5da68452003-01-28 16:08:47 +00001227}
1228
1229/* Create a new ping packet and send it off to peer. */
Harald Weltefed33892017-10-10 09:02:45 +08001230static int create_ping(void *gsn, struct pdp_t *pdp,
1231 struct in_addr *dst, int seq, unsigned int datasize)
Harald Weltebed35df2011-11-02 13:06:18 +01001232{
jjako5da68452003-01-28 16:08:47 +00001233
Harald Weltebed35df2011-11-02 13:06:18 +01001234 struct ip_ping pack;
1235 uint16_t *p = (uint16_t *) & pack;
1236 uint8_t *p8 = (uint8_t *) & pack;
1237 struct in_addr src;
1238 unsigned int n;
1239 long int sum = 0;
1240 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001241
Harald Weltebed35df2011-11-02 13:06:18 +01001242 struct timezone tz;
1243 struct timeval *tp =
1244 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001245
Harald Weltebed35df2011-11-02 13:06:18 +01001246 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001247 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001248 "Ping size to large: %d!", datasize);
1249 return -1;
1250 }
jjako5da68452003-01-28 16:08:47 +00001251
Harald Weltebed35df2011-11-02 13:06:18 +01001252 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001253
Harald Weltebed35df2011-11-02 13:06:18 +01001254 pack.ipver = 0x45;
1255 pack.tos = 0x00;
1256 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1257 pack.fragid = 0x0000;
1258 pack.offset = 0x0040;
1259 pack.ttl = 0x40;
1260 pack.protocol = 0x01;
1261 pack.ipcheck = 0x0000;
1262 pack.src = src.s_addr;
1263 pack.dst = dst->s_addr;
1264 pack.type = 0x08;
1265 pack.code = 0x00;
1266 pack.checksum = 0x0000;
1267 pack.ident = 0x0000;
1268 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001269
Harald Weltebed35df2011-11-02 13:06:18 +01001270 /* Generate ICMP payload */
1271 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1272 for (n = 0; n < (datasize); n++)
1273 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001274
Harald Weltebed35df2011-11-02 13:06:18 +01001275 if (datasize >= sizeof(struct timeval))
1276 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001277
Harald Weltebed35df2011-11-02 13:06:18 +01001278 /* Calculate IP header checksum */
1279 p = (uint16_t *) & pack;
1280 count = CREATEPING_IP;
1281 sum = 0;
1282 while (count > 1) {
1283 sum += *p++;
1284 count -= 2;
1285 }
1286 while (sum >> 16)
1287 sum = (sum & 0xffff) + (sum >> 16);
1288 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001289
Harald Weltebed35df2011-11-02 13:06:18 +01001290 /* Calculate ICMP checksum */
1291 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1292 sum = 0;
1293 p = (uint16_t *) & pack;
1294 p += CREATEPING_IP / 2;
1295 while (count > 1) {
1296 sum += *p++;
1297 count -= 2;
1298 }
1299 if (count > 0)
1300 sum += *(unsigned char *)p;
1301 while (sum >> 16)
1302 sum = (sum & 0xffff) + (sum >> 16);
1303 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001304
Harald Weltebed35df2011-11-02 13:06:18 +01001305 ntransmitted++;
1306 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001307}
1308
Harald Weltefed33892017-10-10 09:02:45 +08001309static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001310{
1311
1312 if (tun && options.ipdown)
1313 tun_runscript(tun, options.ipdown);
1314
1315 ipdel((struct iphash_t *)pdp->peer);
1316 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1317
1318 if (1 == options.contexts)
1319 state = 5; /* Disconnected */
1320
1321 return 0;
1322}
jjakoa7cd2492003-04-11 09:40:12 +00001323
Harald Welte6748dc92017-09-24 21:54:59 +08001324/* Link-Local address prefix fe80::/64 */
1325static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1326
jjakoa7cd2492003-04-11 09:40:12 +00001327/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001328static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001329{
1330 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001331 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001332 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001333 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001334
Harald Welte6748dc92017-09-24 21:54:59 +08001335 if (iph->version == 4) {
1336 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1337 printf("Dropping packet with too short IP header\n");
1338 return 0;
1339 }
1340 src.len = 4;
1341 src.v4.s_addr = iph->saddr;
1342 } else if (iph->version == 6) {
1343 /* We only have a single entry in the hash table, and it consists of the link-local
1344 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1345 * addresses to that format before looking up the hash table via ippool_getip() */
1346 src.len = 16;
1347 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1348 /* is a link-local address, we can do the hash lookup 1:1 */
1349 src.v6 = ip6h->ip6_src;
1350 } else {
1351 /* it is not a link-local address, so we must convert from the /64 prefix
1352 * to the link-local format that's used in the hash table */
1353 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1354 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1355 }
1356 } else {
1357 printf("Dropping packet with invalid IP version %u\n", iph->version);
1358 return 0;
1359 }
jjakoa7cd2492003-04-11 09:40:12 +00001360
Harald Weltebed35df2011-11-02 13:06:18 +01001361 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001362 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001363 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001364 return 0;
1365 }
1366
1367 if (ipm->pdp) /* Check if a peer protocol is defined */
1368 gtp_data_req(gsn, ipm->pdp, pack, len);
1369 return 0;
jjako52c24142002-12-16 13:33:51 +00001370}
1371
Harald Weltefed33892017-10-10 09:02:45 +08001372static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001373{
Harald Welted12eab92017-08-02 19:49:47 +02001374 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001375
Harald Weltebed35df2011-11-02 13:06:18 +01001376 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001377
Harald Weltebed35df2011-11-02 13:06:18 +01001378 if (cause < 0) {
1379 printf("Create PDP Context Request timed out\n");
1380 if (iph->pdp->version == 1) {
1381 printf("Retrying with version 0\n");
1382 iph->pdp->version = 0;
1383 gtp_create_context_req(gsn, iph->pdp, iph);
1384 return 0;
1385 } else {
1386 state = 0;
1387 pdp_freepdp(iph->pdp);
1388 iph->pdp = NULL;
1389 return EOF;
1390 }
1391 }
jjako2c381332003-10-21 19:09:53 +00001392
Harald Weltebed35df2011-11-02 13:06:18 +01001393 if (cause != 128) {
1394 printf
1395 ("Received create PDP context response. Cause value: %d\n",
1396 cause);
1397 state = 0;
1398 pdp_freepdp(iph->pdp);
1399 iph->pdp = NULL;
1400 return EOF; /* Not what we expected */
1401 }
jjako52c24142002-12-16 13:33:51 +00001402
Harald Weltea0d281d2017-08-02 21:48:16 +02001403 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001404 printf
1405 ("Received create PDP context response. Cause value: %d\n",
1406 cause);
1407 pdp_freepdp(iph->pdp);
1408 iph->pdp = NULL;
1409 state = 0;
1410 return EOF; /* Not a valid IP address */
1411 }
jjakoa7cd2492003-04-11 09:40:12 +00001412
Harald Weltebed35df2011-11-02 13:06:18 +01001413 printf("Received create PDP context response. IP address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001414 in46a_ntoa(&addr));
1415
1416 switch (addr.len) {
1417 case 16: /* IPv6 */
1418 /* we have to enable the kernel to perform stateless autoconfiguration,
1419 * i.e. send a router solicitation using the lover 64bits of the allocated
1420 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1421 memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1422 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
1423 break;
1424 case 4: /* IPv4 */
1425 break;
1426 }
jjakoa7cd2492003-04-11 09:40:12 +00001427
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001428 if ((options.createif) && (!options.net.len)) {
Harald Welte6748dc92017-09-24 21:54:59 +08001429 size_t prefixlen = 32;
1430 if (addr.len == 16)
1431 prefixlen = 64;
Harald Weltebed35df2011-11-02 13:06:18 +01001432 /* printf("Setting up interface and routing\n"); */
Harald Welte6748dc92017-09-24 21:54:59 +08001433 /* FIXME: use tun_addattr() not tun_setaddr() */
1434 tun_setaddr(tun, &addr, &addr, prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001435 if (options.defaultroute) {
1436 struct in_addr rm;
1437 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001438 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001439 }
1440 if (options.ipup)
1441 tun_runscript(tun, options.ipup);
1442 }
jjako52c24142002-12-16 13:33:51 +00001443
Harald Welte081f30c2017-10-10 09:36:35 +08001444 /* now that ip-up has been executed, check if we are configured to
1445 * accept router advertisements */
1446 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
1447 char *accept_ra, *forwarding;
1448
1449 accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
1450 forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
1451 if (!accept_ra || !forwarding)
1452 printf("Could not open proc file for %s ?!?\n", tun->devname);
1453 else {
1454 if (!strcmp(accept_ra, "0") ||
1455 (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1"))) {
1456 printf("%s is %s, i.e. your tun device is not configured to accept "
1457 "router advertisements; SLAAC will not suceed, please "
1458 "fix your setup!\n");
1459 }
Harald Welte081f30c2017-10-10 09:36:35 +08001460 }
Harald Welteb589e782017-11-06 03:09:35 +09001461 free(accept_ra);
1462 free(forwarding);
Harald Welte081f30c2017-10-10 09:36:35 +08001463 }
1464
Harald Weltebed35df2011-11-02 13:06:18 +01001465 ipset((struct iphash_t *)pdp->peer, &addr);
1466
1467 state = 2; /* Connected */
1468
1469 return 0;
jjako52c24142002-12-16 13:33:51 +00001470}
1471
Harald Weltefed33892017-10-10 09:02:45 +08001472static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001473{
1474 printf("Received delete PDP context response. Cause value: %d\n",
1475 cause);
1476 return 0;
jjako52c24142002-12-16 13:33:51 +00001477}
1478
Harald Weltefed33892017-10-10 09:02:45 +08001479static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001480{
jjako91aaf222003-10-22 10:09:32 +00001481
Harald Weltebed35df2011-11-02 13:06:18 +01001482 if (recovery < 0) {
1483 printf("Echo Request timed out\n");
1484 if (echoversion == 1) {
1485 printf("Retrying with version 0\n");
1486 echoversion = 0;
1487 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1488 return 0;
1489 } else {
1490 state = 0;
1491 return EOF;
1492 }
1493 } else {
1494 printf("Received echo response\n");
1495 if (!options.contexts)
1496 state = 5;
1497 }
1498 return 0;
jjako52c24142002-12-16 13:33:51 +00001499}
1500
Harald Weltefed33892017-10-10 09:02:45 +08001501static int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001502{
1503 /* if (cause < 0) return 0; Some error occurred. We don't care */
1504 switch (type) {
1505 case GTP_ECHO_REQ:
1506 return echo_conf(cause);
1507 case GTP_CREATE_PDP_REQ:
1508 return create_pdp_conf(pdp, cbp, cause);
1509 case GTP_DELETE_PDP_REQ:
1510 if (cause != 128)
1511 return 0; /* Request not accepted. We don't care */
1512 return delete_pdp_conf(pdp, cause);
1513 default:
1514 return 0;
1515 }
jjako52c24142002-12-16 13:33:51 +00001516}
1517
Harald Weltefed33892017-10-10 09:02:45 +08001518static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001519{
1520 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1521 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001522}
1523
1524int main(int argc, char **argv)
1525{
Harald Weltebed35df2011-11-02 13:06:18 +01001526 fd_set fds; /* For select() */
1527 struct timeval idleTime; /* How long to select() */
1528 struct pdp_t *pdp;
1529 int n;
1530 int starttime = time(NULL); /* Time program was started */
1531 int stoptime = 0; /* Time to exit */
1532 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001533 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001534
Harald Weltebed35df2011-11-02 13:06:18 +01001535 struct timezone tz; /* Used for calculating ping times */
1536 struct timeval tv;
1537 int diff;
jjako52c24142002-12-16 13:33:51 +00001538
bjovana8f71eb2017-02-24 17:39:20 +01001539 signal(SIGTERM, signal_handler);
1540 signal(SIGHUP, signal_handler);
1541 signal(SIGINT, signal_handler);
1542
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001543 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001544
Harald Weltebed35df2011-11-02 13:06:18 +01001545 /* Process options given in configuration file and command line */
1546 if (process_options(argc, argv))
1547 exit(1);
jjako52c24142002-12-16 13:33:51 +00001548
Harald Weltebed35df2011-11-02 13:06:18 +01001549 printf("\nInitialising GTP library\n");
1550 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001551 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001552 exit(1);
1553 }
1554 if (gsn->fd0 > maxfd)
1555 maxfd = gsn->fd0;
1556 if (gsn->fd1c > maxfd)
1557 maxfd = gsn->fd1c;
1558 if (gsn->fd1u > maxfd)
1559 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001560
Harald Weltebed35df2011-11-02 13:06:18 +01001561 gtp_set_cb_delete_context(gsn, delete_context);
1562 gtp_set_cb_conf(gsn, conf);
1563 if (options.createif)
1564 gtp_set_cb_data_ind(gsn, encaps_tun);
1565 else
1566 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001567
Harald Weltebed35df2011-11-02 13:06:18 +01001568 if (options.createif) {
1569 printf("Setting up interface\n");
1570 /* Create a tunnel interface */
Harald Welte73abc382017-10-10 08:50:11 +08001571 if (tun_new((struct tun_t **)&tun, options.tun_dev_name)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001572 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001573 "Failed to create tun");
1574 exit(1);
1575 }
1576 tun_set_cb_ind(tun, cb_tun_ind);
1577 if (tun->fd > maxfd)
1578 maxfd = tun->fd;
1579 }
jjakoa7cd2492003-04-11 09:40:12 +00001580
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001581 if ((options.createif) && (options.net.len)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001582 /* printf("Setting up interface and routing\n"); */
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001583 tun_addaddr(tun, &options.netaddr, &options.destaddr, options.prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001584 if (options.defaultroute) {
1585 struct in_addr rm;
1586 rm.s_addr = 0;
Pau Espin Pedrolf5e40b72017-12-14 14:01:23 +01001587 tun_addroute(tun, &rm, &options.destaddr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001588 }
1589 if (options.ipup)
1590 tun_runscript(tun, options.ipup);
1591 }
jjakoa7cd2492003-04-11 09:40:12 +00001592
Harald Weltebed35df2011-11-02 13:06:18 +01001593 /* Initialise hash tables */
1594 memset(&iphash, 0, sizeof(iphash));
1595 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001596
Harald Weltebed35df2011-11-02 13:06:18 +01001597 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001598
Harald Weltebed35df2011-11-02 13:06:18 +01001599 /* See if anybody is there */
1600 printf("Sending off echo request\n");
1601 echoversion = options.gtpversion;
1602 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001603
Harald Weltebed35df2011-11-02 13:06:18 +01001604 for (n = 0; n < options.contexts; n++) {
1605 uint64_t myimsi;
1606 printf("Setting up PDP context #%d\n", n);
1607 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001608
Harald Weltebed35df2011-11-02 13:06:18 +01001609 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001610
Harald Weltebed35df2011-11-02 13:06:18 +01001611 /* Allocated here. */
1612 /* If create context failes we have to deallocate ourselves. */
1613 /* Otherwise it is deallocated by gtplib */
1614 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001615
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +01001616 pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
Harald Weltebed35df2011-11-02 13:06:18 +01001617 pdp->ipif = tun; /* TODO */
1618 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001619
Harald Weltebed35df2011-11-02 13:06:18 +01001620 if (options.gtpversion == 0) {
1621 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001622 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001623 "QoS length too big");
1624 exit(1);
1625 } else {
1626 memcpy(pdp->qos_req0, options.qos.v,
1627 options.qos.l);
1628 }
1629 }
jjakoa7cd2492003-04-11 09:40:12 +00001630
Harald Weltebed35df2011-11-02 13:06:18 +01001631 pdp->qos_req.l = options.qos.l;
1632 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001633
Harald Weltebed35df2011-11-02 13:06:18 +01001634 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001635
Harald Weltebed35df2011-11-02 13:06:18 +01001636 pdp->rattype.l = options.rattype.l;
1637 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1638 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001639
Harald Weltebed35df2011-11-02 13:06:18 +01001640 pdp->userloc.l = options.userloc.l;
1641 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1642 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001643
Harald Weltebed35df2011-11-02 13:06:18 +01001644 pdp->rai.l = options.rai.l;
1645 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1646 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001647
Harald Weltebed35df2011-11-02 13:06:18 +01001648 pdp->mstz.l = options.mstz.l;
1649 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1650 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001651
Harald Weltebed35df2011-11-02 13:06:18 +01001652 pdp->imeisv.l = options.imeisv.l;
1653 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1654 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001655
Harald Weltebed35df2011-11-02 13:06:18 +01001656 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001657
Harald Weltebed35df2011-11-02 13:06:18 +01001658 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001659 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001660 "APN length too big");
1661 exit(1);
1662 } else {
1663 pdp->apn_use.l = options.apn.l;
1664 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1665 }
jjako193e8b12003-11-10 12:31:41 +00001666
Harald Weltebed35df2011-11-02 13:06:18 +01001667 pdp->gsnlc.l = sizeof(options.listen);
1668 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1669 pdp->gsnlu.l = sizeof(options.listen);
1670 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001671
Harald Weltebed35df2011-11-02 13:06:18 +01001672 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001673 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001674 "MSISDN length too big");
1675 exit(1);
1676 } else {
1677 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1678 }
jjakob62c3dd2004-05-27 18:51:55 +00001679
Harald Welte840a8e92017-09-24 18:12:40 +08001680 /* Request dynamic IP address */
1681 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1682 pdp->eua.v[1] = options.pdp_type;
1683 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001684
Harald Weltebed35df2011-11-02 13:06:18 +01001685 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001686 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001687 "PCO length too big");
1688 exit(1);
1689 } else {
1690 pdp->pco_req.l = options.pco.l;
1691 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1692 }
jjako52c24142002-12-16 13:33:51 +00001693
Harald Weltebed35df2011-11-02 13:06:18 +01001694 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001695
Harald Weltebed35df2011-11-02 13:06:18 +01001696 pdp->hisaddr0 = options.remote;
1697 pdp->hisaddr1 = options.remote;
1698
Pau Espin Pedrol7c4de072017-12-14 13:59:02 +01001699 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
Harald Weltebed35df2011-11-02 13:06:18 +01001700 512 = Flat rate, 256 = Hot billing */
1701
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001702 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1703
Harald Weltebed35df2011-11-02 13:06:18 +01001704 /* Create context */
1705 /* We send this of once. Retransmissions are handled by gtplib */
1706 gtp_create_context_req(gsn, pdp, &iparr[n]);
1707 }
1708
1709 state = 1; /* Enter wait_connection state */
1710
1711 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001712
jjako52c24142002-12-16 13:33:51 +00001713 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001714 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001715 /******************************************************************/
1716
Harald Weltebed35df2011-11-02 13:06:18 +01001717 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001718
Harald Weltebed35df2011-11-02 13:06:18 +01001719 /* Take down client after timeout after disconnect */
1720 if ((4 == state) && ((stoptime) <= time(NULL))) {
1721 state = 5;
1722 }
jjako7b8fad42003-07-07 14:37:42 +00001723
Harald Weltebed35df2011-11-02 13:06:18 +01001724 /* Take down client after timelimit timeout */
1725 if ((2 == state) && (options.timelimit) &&
1726 ((starttime + options.timelimit) <= time(NULL))) {
1727 state = 3;
1728 }
jjako7b8fad42003-07-07 14:37:42 +00001729
Harald Weltebed35df2011-11-02 13:06:18 +01001730 /* Take down client after ping timeout */
1731 if ((2 == state) && (pingtimeout)
1732 && (pingtimeout <= time(NULL))) {
1733 state = 3;
1734 }
jjako7b8fad42003-07-07 14:37:42 +00001735
Harald Weltebed35df2011-11-02 13:06:18 +01001736 /* Set pingtimeout for later disconnection */
1737 if (options.pingcount && ntransmitted >= options.pingcount) {
1738 pingtimeout = time(NULL) + 5; /* Extra seconds */
1739 }
jjako7b8fad42003-07-07 14:37:42 +00001740
Harald Weltebed35df2011-11-02 13:06:18 +01001741 /* Print statistics if no more ping packets are missing */
1742 if (ntransmitted && options.pingcount
1743 && nreceived >= options.pingcount) {
1744 ping_finish();
1745 if (!options.createif)
1746 state = 3;
1747 }
jjako7b8fad42003-07-07 14:37:42 +00001748
Harald Weltebed35df2011-11-02 13:06:18 +01001749 /* Send off disconnect */
1750 if (3 == state) {
1751 state = 4;
1752 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1753 for (n = 0; n < options.contexts; n++) {
1754 /* Delete context */
1755 printf("Disconnecting PDP context #%d\n", n);
1756 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1757 1);
1758 if ((options.pinghost.s_addr != 0)
1759 && ntransmitted)
1760 ping_finish();
1761 }
1762 }
jjako7b8fad42003-07-07 14:37:42 +00001763
Harald Weltebed35df2011-11-02 13:06:18 +01001764 /* Send of ping packets */
1765 diff = 0;
1766 while ((diff <= 0) &&
1767 /* Send off an ICMP ping packet */
1768 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1769 ((pingseq < options.pingcount)
1770 || (options.pingcount == 0))) {
1771 if (!pingseq)
1772 gettimeofday(&firstping, &tz); /* Set time of first ping */
1773 gettimeofday(&tv, &tz);
1774 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1775 if (diff <= 0) {
1776 if (options.debug)
1777 printf("Create_ping %d\n", diff);
1778 create_ping(gsn,
1779 iparr[pingseq %
1780 options.contexts].pdp,
1781 &options.pinghost, pingseq,
1782 options.pingsize);
1783 pingseq++;
1784 }
1785 }
jjako5da68452003-01-28 16:08:47 +00001786
Harald Weltebed35df2011-11-02 13:06:18 +01001787 FD_ZERO(&fds);
1788 if (tun)
1789 FD_SET(tun->fd, &fds);
1790 FD_SET(gsn->fd0, &fds);
1791 FD_SET(gsn->fd1c, &fds);
1792 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001793
Harald Weltebed35df2011-11-02 13:06:18 +01001794 gtp_retranstimeout(gsn, &idleTime);
1795 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001796
Harald Weltebed35df2011-11-02 13:06:18 +01001797 if (options.debug)
1798 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1799 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001800
bjovana8f71eb2017-02-24 17:39:20 +01001801 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001802 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1803 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001804 if (errno == EINTR)
1805 signal_received = 1;
1806 else
1807 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1808 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001809 break;
1810 case 0:
1811 gtp_retrans(gsn); /* Only retransmit if nothing else */
1812 break;
1813 default:
1814 break;
1815 }
1816
bjovana8f71eb2017-02-24 17:39:20 +01001817 if (!signal_received) {
1818
1819 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1820 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1821 "TUN decaps failed");
1822 }
1823
1824 if (FD_ISSET(gsn->fd0, &fds))
1825 gtp_decaps0(gsn);
1826
1827 if (FD_ISSET(gsn->fd1c, &fds))
1828 gtp_decaps1c(gsn);
1829
1830 if (FD_ISSET(gsn->fd1u, &fds))
1831 gtp_decaps1u(gsn);
1832
Harald Weltebed35df2011-11-02 13:06:18 +01001833 }
Harald Weltebed35df2011-11-02 13:06:18 +01001834 }
1835
1836 gtp_free(gsn); /* Clean up the gsn instance */
1837
1838 if (options.createif)
1839 tun_free(tun);
1840
1841 if (0 == state)
1842 exit(1); /* Indicate error */
1843
1844 return 0;
jjako52c24142002-12-16 13:33:51 +00001845}