blob: 300183b89f340fd27b5b06c4f3f74d0e7d1bdbec [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
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>
jjako52c24142002-12-16 13:33:51 +00005 *
6 * 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.
10 *
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;
Harald Welted12eab92017-08-02 19:49:47 +020088 struct in_addr netaddr, destaddr, net; /* Network interface */
89 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 */
375 /* Do not allow sgsnemu to run as deamon
376 if (!args_info.fg_flag)
377 {
378 closelog();
379 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) {
Harald Welted12eab92017-08-02 19:49:47 +0200876 struct in46_addr in46;
Harald Weltebed35df2011-11-02 13:06:18 +0100877 if (ippool_aton
Harald Welted12eab92017-08-02 19:49:47 +0200878 (&in46, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100879 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100880 "Invalid network address: %s!",
881 args_info.net_arg);
882 exit(1);
883 }
Harald Welted12eab92017-08-02 19:49:47 +0200884 options.net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100885 options.netaddr.s_addr = options.net.s_addr;
886 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000887
Harald Weltebed35df2011-11-02 13:06:18 +0100888 } else {
889 options.net.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200890 options.prefixlen = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100891 options.netaddr.s_addr = 0;
892 options.destaddr.s_addr = 0;
893 }
jjako193e8b12003-11-10 12:31:41 +0000894
Harald Weltebed35df2011-11-02 13:06:18 +0100895 /* ipup */
896 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000897
Harald Weltebed35df2011-11-02 13:06:18 +0100898 /* ipdown */
899 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000900
Harald Weltebed35df2011-11-02 13:06:18 +0100901 /* statedir */
902 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000903
Harald Weltebed35df2011-11-02 13:06:18 +0100904 /* defaultroute */
905 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000906
Harald Weltebed35df2011-11-02 13:06:18 +0100907 /* pinghost */
908 /* Store ping host as in_addr */
909 if (args_info.pinghost_arg) {
910 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100911 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100912 "Invalid ping host: %s!",
913 args_info.pinghost_arg);
914 return -1;
915 } else {
916 memcpy(&options.pinghost.s_addr, host->h_addr,
917 host->h_length);
918 printf("Using ping host: %s (%s)\n",
919 args_info.pinghost_arg,
920 inet_ntoa(options.pinghost));
921 }
922 }
jjakoa7cd2492003-04-11 09:40:12 +0000923
Harald Weltebed35df2011-11-02 13:06:18 +0100924 /* Other ping parameters */
925 options.pingrate = args_info.pingrate_arg;
926 options.pingsize = args_info.pingsize_arg;
927 options.pingcount = args_info.pingcount_arg;
928 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000929
Harald Weltebed35df2011-11-02 13:06:18 +0100930 /* norecovery */
931 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000932
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800933 if (args_info.no_tx_gpdu_seq_flag)
934 options.tx_gpdu_seq = 0;
935 else
936 options.tx_gpdu_seq = 1;
937
Harald Welte840a8e92017-09-24 18:12:40 +0800938 /* PDP Type */
939 if (!strcmp(args_info.pdp_type_arg, "v6"))
940 options.pdp_type = PDP_EUA_TYPE_v6;
Harald Welte6748dc92017-09-24 21:54:59 +0800941 else if (!strcmp(args_info.pdp_type_arg, "v4"))
Harald Welte840a8e92017-09-24 18:12:40 +0800942 options.pdp_type = PDP_EUA_TYPE_v4;
Harald Welte6748dc92017-09-24 21:54:59 +0800943 else {
944 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Unsupported/unknown PDP Type '%s'\n",
945 args_info.pdp_type_arg);
946 return -1;
947 }
948
949 if (options.pingcount && options.pdp_type != PDP_EUA_TYPE_v4) {
950 SYS_ERR(DSGSN, LOGL_ERROR, 0, "built-in ping only works with IPv4, use tun-device");
951 return -1;
952 }
Harald Welte840a8e92017-09-24 18:12:40 +0800953
Harald Weltebed35df2011-11-02 13:06:18 +0100954 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000955
956}
957
Harald Welte081f30c2017-10-10 09:36:35 +0800958/* read a single value from a /procc file, up to 255 bytes, callee-allocated */
959static char *proc_read(const char *path)
960{
961 char *ret = NULL;
962 FILE *f;
963
964 f = fopen(path, "r");
965 if (!f)
966 return NULL;
967
968 ret = malloc(256);
969 if (!ret)
970 goto out;
971
972 if (!fgets(ret, 256, f)) {
973 free(ret);
974 ret = NULL;
975 goto out;
976 }
Harald Welte081f30c2017-10-10 09:36:35 +0800977
978out:
979 fclose(f);
980 return ret;
981}
982
983/* Read value of a /proc/sys/net/ipv6/conf file for given device.
984 * Memory is dynamically allocated, caller must free it later. */
985static char *proc_ipv6_conf_read(const char *dev, const char *file)
986{
987 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
Harald Welteb11ed0f2017-11-06 03:07:26 +0900988 char path[strlen(fmt) + strlen(dev) + strlen(file)+1];
Harald Welte081f30c2017-10-10 09:36:35 +0800989 snprintf(path, sizeof(path), fmt, dev, file);
990 return proc_read(path);
991}
992
Harald Weltefed33892017-10-10 09:02:45 +0800993static char *print_ipprot(int t)
Harald Weltebed35df2011-11-02 13:06:18 +0100994{
Harald Weltee37f48e2017-10-10 09:05:50 +0800995 struct protoent *pe = getprotobynumber(t);
996
997 if (!pe)
Harald Weltebed35df2011-11-02 13:06:18 +0100998 return "Unknown";
Harald Weltee37f48e2017-10-10 09:05:50 +0800999 else
1000 return pe->p_name;
jjako5da68452003-01-28 16:08:47 +00001001}
1002
Harald Weltefed33892017-10-10 09:02:45 +08001003static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001004{
1005 static char *ttab[] = {
1006 "Echo Reply",
1007 "ICMP 1",
1008 "ICMP 2",
1009 "Dest Unreachable",
1010 "Source Quench",
1011 "Redirect",
1012 "ICMP 6",
1013 "ICMP 7",
1014 "Echo",
1015 "ICMP 9",
1016 "ICMP 10",
1017 "Time Exceeded",
1018 "Parameter Problem",
1019 "Timestamp",
1020 "Timestamp Reply",
1021 "Info Request",
1022 "Info Reply"
1023 };
1024 if (t < 0 || t > 16)
1025 return ("OUT-OF-RANGE");
1026 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001027}
1028
Harald Weltefed33892017-10-10 09:02:45 +08001029static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001030{
1031 unsigned int n;
1032 uint64_t i64 = 0;
1033 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1034 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001035
Harald Weltebed35df2011-11-02 13:06:18 +01001036 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1037 /* ul16_t format always starts with 0x91 to indicate international format */
1038 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1039 for (n = 0; n < src->l; n++) {
1040 if ((src->v[n] & 0x0f) != 0x0f) {
1041 i64 *= 10;
1042 i64 += src->v[n] & 0x0f;
1043 }
1044 if ((src->v[n] & 0xf0) != 0xf0) {
1045 i64 *= 10;
1046 i64 += (src->v[n] & 0xf0) >> 4;
1047 }
1048 }
jjako193e8b12003-11-10 12:31:41 +00001049
Harald Weltebed35df2011-11-02 13:06:18 +01001050 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001051
Harald Weltebed35df2011-11-02 13:06:18 +01001052 /* Generate array with least significant digit in first octet */
1053 while (i64) {
1054 msa[msalen++] = i64 % 10;
1055 i64 = i64 / 10;
1056 }
jjako193e8b12003-11-10 12:31:41 +00001057
Harald Weltebed35df2011-11-02 13:06:18 +01001058 /* Convert back to ul16_t format */
1059 for (n = 0; n < msalen; n++) {
1060 if ((n % 2) == 0) {
1061 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1062 dst->l += 1;
1063 } else {
1064 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1065 msa[msalen - n - 1] * 16;
1066 }
1067 }
jjako193e8b12003-11-10 12:31:41 +00001068
Harald Weltebed35df2011-11-02 13:06:18 +01001069 return 0;
jjako193e8b12003-11-10 12:31:41 +00001070
1071}
1072
Harald Weltefed33892017-10-10 09:02:45 +08001073static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001074{
1075 /* TODO: big endian / small endian ??? */
1076 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001077
Harald Weltebed35df2011-11-02 13:06:18 +01001078 /* Convert from uint64_t bcd to uint64_t integer format */
1079 /* The resulting integer format is multiplied by 10 */
1080 while (src) {
1081 if ((src & 0x0f) != 0x0f) {
1082 i64 *= 10;
1083 i64 += (src & 0x0f);
1084 }
1085 if ((src & 0xf0) != 0xf0) {
1086 i64 *= 10;
1087 i64 += (src & 0xf0) >> 4;
1088 }
1089 src = src >> 8;
1090 }
jjako193e8b12003-11-10 12:31:41 +00001091
Harald Weltebed35df2011-11-02 13:06:18 +01001092 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001093
Harald Weltebed35df2011-11-02 13:06:18 +01001094 *dst = 0;
1095 while (i64) {
1096 *dst = *dst << 4;
1097 *dst += (i64 % 10);
1098 i64 = i64 / 10;
1099 }
jjako193e8b12003-11-10 12:31:41 +00001100
Harald Weltebed35df2011-11-02 13:06:18 +01001101 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001102
Harald Weltebed35df2011-11-02 13:06:18 +01001103 return 0;
jjako193e8b12003-11-10 12:31:41 +00001104
1105}
1106
jjakoafb2a972003-01-29 21:04:13 +00001107/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001108static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001109{
1110 struct timezone tz;
1111 struct timeval tv;
1112 int diff;
1113 if ((options.pinghost.s_addr) && (2 == state) &&
1114 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1115 gettimeofday(&tv, &tz);
1116 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1117 tp->tv_sec = 0;
1118 if (diff > 0)
1119 tp->tv_usec = diff;
1120 else {
1121 /* For some reason we get packet loss if set to zero */
1122 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1123 tp->tv_usec = 0;
1124 }
1125 }
1126 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001127}
1128
jjako5da68452003-01-28 16:08:47 +00001129/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001130static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001131{
Harald Weltebed35df2011-11-02 13:06:18 +01001132 struct timezone tz;
1133 struct timeval tv;
1134 int elapsed;
1135 gettimeofday(&tv, &tz);
1136 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1137 printf("\n");
1138 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1139 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1140 elapsed / 1000000.0);
1141 printf("%d packets received, ", nreceived);
1142 if (ntransmitted) {
1143 if (nreceived > ntransmitted)
1144 printf("-- somebody's printing up packets!");
1145 else
1146 printf("%d%% packet loss",
1147 (int)(((ntransmitted - nreceived) * 100) /
1148 ntransmitted));
1149 }
1150 printf("\n");
1151 if (options.debug)
1152 printf("%d packets received in total\n", ntreceived);
1153 if (nreceived && tsum)
1154 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1155 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1156 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001157
Harald Weltebed35df2011-11-02 13:06:18 +01001158 ntransmitted = 0;
1159 return 0;
jjako5da68452003-01-28 16:08:47 +00001160}
1161
1162/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltefed33892017-10-10 09:02:45 +08001163static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001164{
1165 struct timezone tz;
1166 struct timeval tv;
1167 struct timeval *tp;
1168 struct ip_ping *pingpack = pack;
1169 struct in_addr src;
1170 int triptime;
jjako5da68452003-01-28 16:08:47 +00001171
Harald Weltebed35df2011-11-02 13:06:18 +01001172 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001173
Harald Weltebed35df2011-11-02 13:06:18 +01001174 gettimeofday(&tv, &tz);
1175 if (options.debug)
1176 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001177
Harald Weltebed35df2011-11-02 13:06:18 +01001178 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1179 printf("packet too short (%d bytes) from %s\n", len,
1180 inet_ntoa(src));
1181 return 0;
1182 }
jjako5da68452003-01-28 16:08:47 +00001183
Harald Weltebed35df2011-11-02 13:06:18 +01001184 ntreceived++;
1185 if (pingpack->protocol != 1) {
1186 if (!options.pingquiet)
1187 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1188 len, inet_ntoa(src), pingpack->protocol,
1189 print_ipprot(pingpack->protocol));
1190 return 0;
1191 }
jjako5da68452003-01-28 16:08:47 +00001192
Harald Weltebed35df2011-11-02 13:06:18 +01001193 if (pingpack->type != 0) {
1194 if (!options.pingquiet)
1195 printf
1196 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1197 len, inet_ntoa(src), pingpack->type,
1198 print_icmptype(pingpack->type), pingpack->code);
1199 return 0;
1200 }
jjako5da68452003-01-28 16:08:47 +00001201
Harald Weltebed35df2011-11-02 13:06:18 +01001202 nreceived++;
1203 if (!options.pingquiet)
1204 printf("%d bytes from %s: icmp_seq=%d", len,
1205 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001206
Harald Weltebed35df2011-11-02 13:06:18 +01001207 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1208 gettimeofday(&tv, &tz);
1209 tp = (struct timeval *)pingpack->data;
1210 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1211 tv.tv_sec--;
1212 tv.tv_usec += 1000000;
1213 }
1214 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001215
Harald Weltebed35df2011-11-02 13:06:18 +01001216 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1217 tsum += triptime;
1218 if (triptime < tmin)
1219 tmin = triptime;
1220 if (triptime > tmax)
1221 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001222
Harald Weltebed35df2011-11-02 13:06:18 +01001223 if (!options.pingquiet)
1224 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001225
Harald Weltebed35df2011-11-02 13:06:18 +01001226 } else if (!options.pingquiet)
1227 printf("\n");
1228 return 0;
jjako5da68452003-01-28 16:08:47 +00001229}
1230
1231/* Create a new ping packet and send it off to peer. */
Harald Weltefed33892017-10-10 09:02:45 +08001232static int create_ping(void *gsn, struct pdp_t *pdp,
1233 struct in_addr *dst, int seq, unsigned int datasize)
Harald Weltebed35df2011-11-02 13:06:18 +01001234{
jjako5da68452003-01-28 16:08:47 +00001235
Harald Weltebed35df2011-11-02 13:06:18 +01001236 struct ip_ping pack;
1237 uint16_t *p = (uint16_t *) & pack;
1238 uint8_t *p8 = (uint8_t *) & pack;
1239 struct in_addr src;
1240 unsigned int n;
1241 long int sum = 0;
1242 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001243
Harald Weltebed35df2011-11-02 13:06:18 +01001244 struct timezone tz;
1245 struct timeval *tp =
1246 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001247
Harald Weltebed35df2011-11-02 13:06:18 +01001248 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001249 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001250 "Ping size to large: %d!", datasize);
1251 return -1;
1252 }
jjako5da68452003-01-28 16:08:47 +00001253
Harald Weltebed35df2011-11-02 13:06:18 +01001254 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001255
Harald Weltebed35df2011-11-02 13:06:18 +01001256 pack.ipver = 0x45;
1257 pack.tos = 0x00;
1258 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1259 pack.fragid = 0x0000;
1260 pack.offset = 0x0040;
1261 pack.ttl = 0x40;
1262 pack.protocol = 0x01;
1263 pack.ipcheck = 0x0000;
1264 pack.src = src.s_addr;
1265 pack.dst = dst->s_addr;
1266 pack.type = 0x08;
1267 pack.code = 0x00;
1268 pack.checksum = 0x0000;
1269 pack.ident = 0x0000;
1270 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001271
Harald Weltebed35df2011-11-02 13:06:18 +01001272 /* Generate ICMP payload */
1273 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1274 for (n = 0; n < (datasize); n++)
1275 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001276
Harald Weltebed35df2011-11-02 13:06:18 +01001277 if (datasize >= sizeof(struct timeval))
1278 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001279
Harald Weltebed35df2011-11-02 13:06:18 +01001280 /* Calculate IP header checksum */
1281 p = (uint16_t *) & pack;
1282 count = CREATEPING_IP;
1283 sum = 0;
1284 while (count > 1) {
1285 sum += *p++;
1286 count -= 2;
1287 }
1288 while (sum >> 16)
1289 sum = (sum & 0xffff) + (sum >> 16);
1290 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001291
Harald Weltebed35df2011-11-02 13:06:18 +01001292 /* Calculate ICMP checksum */
1293 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1294 sum = 0;
1295 p = (uint16_t *) & pack;
1296 p += CREATEPING_IP / 2;
1297 while (count > 1) {
1298 sum += *p++;
1299 count -= 2;
1300 }
1301 if (count > 0)
1302 sum += *(unsigned char *)p;
1303 while (sum >> 16)
1304 sum = (sum & 0xffff) + (sum >> 16);
1305 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001306
Harald Weltebed35df2011-11-02 13:06:18 +01001307 ntransmitted++;
1308 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001309}
1310
Harald Weltefed33892017-10-10 09:02:45 +08001311static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001312{
1313
1314 if (tun && options.ipdown)
1315 tun_runscript(tun, options.ipdown);
1316
1317 ipdel((struct iphash_t *)pdp->peer);
1318 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1319
1320 if (1 == options.contexts)
1321 state = 5; /* Disconnected */
1322
1323 return 0;
1324}
jjakoa7cd2492003-04-11 09:40:12 +00001325
Harald Welte6748dc92017-09-24 21:54:59 +08001326/* Link-Local address prefix fe80::/64 */
1327static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1328
jjakoa7cd2492003-04-11 09:40:12 +00001329/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001330static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001331{
1332 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001333 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001334 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001335 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001336
Harald Welte6748dc92017-09-24 21:54:59 +08001337 if (iph->version == 4) {
1338 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1339 printf("Dropping packet with too short IP header\n");
1340 return 0;
1341 }
1342 src.len = 4;
1343 src.v4.s_addr = iph->saddr;
1344 } else if (iph->version == 6) {
1345 /* We only have a single entry in the hash table, and it consists of the link-local
1346 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1347 * addresses to that format before looking up the hash table via ippool_getip() */
1348 src.len = 16;
1349 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1350 /* is a link-local address, we can do the hash lookup 1:1 */
1351 src.v6 = ip6h->ip6_src;
1352 } else {
1353 /* it is not a link-local address, so we must convert from the /64 prefix
1354 * to the link-local format that's used in the hash table */
1355 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1356 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1357 }
1358 } else {
1359 printf("Dropping packet with invalid IP version %u\n", iph->version);
1360 return 0;
1361 }
jjakoa7cd2492003-04-11 09:40:12 +00001362
Harald Weltebed35df2011-11-02 13:06:18 +01001363 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001364 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001365 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001366 return 0;
1367 }
1368
1369 if (ipm->pdp) /* Check if a peer protocol is defined */
1370 gtp_data_req(gsn, ipm->pdp, pack, len);
1371 return 0;
jjako52c24142002-12-16 13:33:51 +00001372}
1373
Harald Weltefed33892017-10-10 09:02:45 +08001374static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001375{
Harald Welted12eab92017-08-02 19:49:47 +02001376 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001377
Harald Weltebed35df2011-11-02 13:06:18 +01001378 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001379
Harald Weltebed35df2011-11-02 13:06:18 +01001380 if (cause < 0) {
1381 printf("Create PDP Context Request timed out\n");
1382 if (iph->pdp->version == 1) {
1383 printf("Retrying with version 0\n");
1384 iph->pdp->version = 0;
1385 gtp_create_context_req(gsn, iph->pdp, iph);
1386 return 0;
1387 } else {
1388 state = 0;
1389 pdp_freepdp(iph->pdp);
1390 iph->pdp = NULL;
1391 return EOF;
1392 }
1393 }
jjako2c381332003-10-21 19:09:53 +00001394
Harald Weltebed35df2011-11-02 13:06:18 +01001395 if (cause != 128) {
1396 printf
1397 ("Received create PDP context response. Cause value: %d\n",
1398 cause);
1399 state = 0;
1400 pdp_freepdp(iph->pdp);
1401 iph->pdp = NULL;
1402 return EOF; /* Not what we expected */
1403 }
jjako52c24142002-12-16 13:33:51 +00001404
Harald Weltea0d281d2017-08-02 21:48:16 +02001405 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001406 printf
1407 ("Received create PDP context response. Cause value: %d\n",
1408 cause);
1409 pdp_freepdp(iph->pdp);
1410 iph->pdp = NULL;
1411 state = 0;
1412 return EOF; /* Not a valid IP address */
1413 }
jjakoa7cd2492003-04-11 09:40:12 +00001414
Harald Weltebed35df2011-11-02 13:06:18 +01001415 printf("Received create PDP context response. IP address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001416 in46a_ntoa(&addr));
1417
1418 switch (addr.len) {
1419 case 16: /* IPv6 */
1420 /* we have to enable the kernel to perform stateless autoconfiguration,
1421 * i.e. send a router solicitation using the lover 64bits of the allocated
1422 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1423 memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1424 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
1425 break;
1426 case 4: /* IPv4 */
1427 break;
1428 }
jjakoa7cd2492003-04-11 09:40:12 +00001429
Harald Weltebed35df2011-11-02 13:06:18 +01001430 if ((options.createif) && (!options.net.s_addr)) {
Harald Welte6748dc92017-09-24 21:54:59 +08001431 size_t prefixlen = 32;
1432 if (addr.len == 16)
1433 prefixlen = 64;
Harald Weltebed35df2011-11-02 13:06:18 +01001434 /* printf("Setting up interface and routing\n"); */
Harald Welte6748dc92017-09-24 21:54:59 +08001435 /* FIXME: use tun_addattr() not tun_setaddr() */
1436 tun_setaddr(tun, &addr, &addr, prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001437 if (options.defaultroute) {
1438 struct in_addr rm;
1439 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001440 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001441 }
1442 if (options.ipup)
1443 tun_runscript(tun, options.ipup);
1444 }
jjako52c24142002-12-16 13:33:51 +00001445
Harald Welte081f30c2017-10-10 09:36:35 +08001446 /* now that ip-up has been executed, check if we are configured to
1447 * accept router advertisements */
1448 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
1449 char *accept_ra, *forwarding;
1450
1451 accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
1452 forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
1453 if (!accept_ra || !forwarding)
1454 printf("Could not open proc file for %s ?!?\n", tun->devname);
1455 else {
1456 if (!strcmp(accept_ra, "0") ||
1457 (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1"))) {
1458 printf("%s is %s, i.e. your tun device is not configured to accept "
1459 "router advertisements; SLAAC will not suceed, please "
1460 "fix your setup!\n");
1461 }
Harald Welte081f30c2017-10-10 09:36:35 +08001462 }
Harald Welteb589e782017-11-06 03:09:35 +09001463 free(accept_ra);
1464 free(forwarding);
Harald Welte081f30c2017-10-10 09:36:35 +08001465 }
1466
Harald Weltebed35df2011-11-02 13:06:18 +01001467 ipset((struct iphash_t *)pdp->peer, &addr);
1468
1469 state = 2; /* Connected */
1470
1471 return 0;
jjako52c24142002-12-16 13:33:51 +00001472}
1473
Harald Weltefed33892017-10-10 09:02:45 +08001474static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001475{
1476 printf("Received delete PDP context response. Cause value: %d\n",
1477 cause);
1478 return 0;
jjako52c24142002-12-16 13:33:51 +00001479}
1480
Harald Weltefed33892017-10-10 09:02:45 +08001481static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001482{
jjako91aaf222003-10-22 10:09:32 +00001483
Harald Weltebed35df2011-11-02 13:06:18 +01001484 if (recovery < 0) {
1485 printf("Echo Request timed out\n");
1486 if (echoversion == 1) {
1487 printf("Retrying with version 0\n");
1488 echoversion = 0;
1489 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1490 return 0;
1491 } else {
1492 state = 0;
1493 return EOF;
1494 }
1495 } else {
1496 printf("Received echo response\n");
1497 if (!options.contexts)
1498 state = 5;
1499 }
1500 return 0;
jjako52c24142002-12-16 13:33:51 +00001501}
1502
Harald Weltefed33892017-10-10 09:02:45 +08001503static int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001504{
1505 /* if (cause < 0) return 0; Some error occurred. We don't care */
1506 switch (type) {
1507 case GTP_ECHO_REQ:
1508 return echo_conf(cause);
1509 case GTP_CREATE_PDP_REQ:
1510 return create_pdp_conf(pdp, cbp, cause);
1511 case GTP_DELETE_PDP_REQ:
1512 if (cause != 128)
1513 return 0; /* Request not accepted. We don't care */
1514 return delete_pdp_conf(pdp, cause);
1515 default:
1516 return 0;
1517 }
jjako52c24142002-12-16 13:33:51 +00001518}
1519
Harald Weltefed33892017-10-10 09:02:45 +08001520static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001521{
1522 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1523 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001524}
1525
1526int main(int argc, char **argv)
1527{
Harald Weltebed35df2011-11-02 13:06:18 +01001528 fd_set fds; /* For select() */
1529 struct timeval idleTime; /* How long to select() */
1530 struct pdp_t *pdp;
1531 int n;
1532 int starttime = time(NULL); /* Time program was started */
1533 int stoptime = 0; /* Time to exit */
1534 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001535 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001536
Harald Weltebed35df2011-11-02 13:06:18 +01001537 struct timezone tz; /* Used for calculating ping times */
1538 struct timeval tv;
1539 int diff;
jjako52c24142002-12-16 13:33:51 +00001540
bjovana8f71eb2017-02-24 17:39:20 +01001541 signal(SIGTERM, signal_handler);
1542 signal(SIGHUP, signal_handler);
1543 signal(SIGINT, signal_handler);
1544
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001545 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001546
Harald Weltebed35df2011-11-02 13:06:18 +01001547 /* Process options given in configuration file and command line */
1548 if (process_options(argc, argv))
1549 exit(1);
jjako52c24142002-12-16 13:33:51 +00001550
Harald Weltebed35df2011-11-02 13:06:18 +01001551 printf("\nInitialising GTP library\n");
1552 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001553 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001554 exit(1);
1555 }
1556 if (gsn->fd0 > maxfd)
1557 maxfd = gsn->fd0;
1558 if (gsn->fd1c > maxfd)
1559 maxfd = gsn->fd1c;
1560 if (gsn->fd1u > maxfd)
1561 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001562
Harald Weltebed35df2011-11-02 13:06:18 +01001563 gtp_set_cb_delete_context(gsn, delete_context);
1564 gtp_set_cb_conf(gsn, conf);
1565 if (options.createif)
1566 gtp_set_cb_data_ind(gsn, encaps_tun);
1567 else
1568 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001569
Harald Weltebed35df2011-11-02 13:06:18 +01001570 if (options.createif) {
1571 printf("Setting up interface\n");
1572 /* Create a tunnel interface */
Harald Welte73abc382017-10-10 08:50:11 +08001573 if (tun_new((struct tun_t **)&tun, options.tun_dev_name)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001574 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001575 "Failed to create tun");
1576 exit(1);
1577 }
1578 tun_set_cb_ind(tun, cb_tun_ind);
1579 if (tun->fd > maxfd)
1580 maxfd = tun->fd;
1581 }
jjakoa7cd2492003-04-11 09:40:12 +00001582
Harald Weltebed35df2011-11-02 13:06:18 +01001583 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001584 struct in_addr mask;
1585 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001586 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001587 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001588 if (options.defaultroute) {
1589 struct in_addr rm;
1590 rm.s_addr = 0;
1591 tun_addroute(tun, &rm, &options.destaddr, &rm);
1592 }
1593 if (options.ipup)
1594 tun_runscript(tun, options.ipup);
1595 }
jjakoa7cd2492003-04-11 09:40:12 +00001596
Harald Weltebed35df2011-11-02 13:06:18 +01001597 /* Initialise hash tables */
1598 memset(&iphash, 0, sizeof(iphash));
1599 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001600
Harald Weltebed35df2011-11-02 13:06:18 +01001601 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001602
Harald Weltebed35df2011-11-02 13:06:18 +01001603 /* See if anybody is there */
1604 printf("Sending off echo request\n");
1605 echoversion = options.gtpversion;
1606 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001607
Harald Weltebed35df2011-11-02 13:06:18 +01001608 for (n = 0; n < options.contexts; n++) {
1609 uint64_t myimsi;
1610 printf("Setting up PDP context #%d\n", n);
1611 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001612
Harald Weltebed35df2011-11-02 13:06:18 +01001613 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001614
Harald Weltebed35df2011-11-02 13:06:18 +01001615 /* Allocated here. */
1616 /* If create context failes we have to deallocate ourselves. */
1617 /* Otherwise it is deallocated by gtplib */
1618 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001619
Pau Espin Pedrol2d6a69e2017-12-06 19:26:25 +01001620 pdp->peer[0] = &iparr[n]; /* FIXME: support v4v6, have 2 peers */
Harald Weltebed35df2011-11-02 13:06:18 +01001621 pdp->ipif = tun; /* TODO */
1622 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001623
Harald Weltebed35df2011-11-02 13:06:18 +01001624 if (options.gtpversion == 0) {
1625 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001626 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001627 "QoS length too big");
1628 exit(1);
1629 } else {
1630 memcpy(pdp->qos_req0, options.qos.v,
1631 options.qos.l);
1632 }
1633 }
jjakoa7cd2492003-04-11 09:40:12 +00001634
Harald Weltebed35df2011-11-02 13:06:18 +01001635 pdp->qos_req.l = options.qos.l;
1636 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001637
Harald Weltebed35df2011-11-02 13:06:18 +01001638 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001639
Harald Weltebed35df2011-11-02 13:06:18 +01001640 pdp->rattype.l = options.rattype.l;
1641 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1642 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001643
Harald Weltebed35df2011-11-02 13:06:18 +01001644 pdp->userloc.l = options.userloc.l;
1645 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1646 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001647
Harald Weltebed35df2011-11-02 13:06:18 +01001648 pdp->rai.l = options.rai.l;
1649 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1650 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001651
Harald Weltebed35df2011-11-02 13:06:18 +01001652 pdp->mstz.l = options.mstz.l;
1653 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1654 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001655
Harald Weltebed35df2011-11-02 13:06:18 +01001656 pdp->imeisv.l = options.imeisv.l;
1657 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1658 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001659
Harald Weltebed35df2011-11-02 13:06:18 +01001660 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001661
Harald Weltebed35df2011-11-02 13:06:18 +01001662 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001663 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001664 "APN length too big");
1665 exit(1);
1666 } else {
1667 pdp->apn_use.l = options.apn.l;
1668 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1669 }
jjako193e8b12003-11-10 12:31:41 +00001670
Harald Weltebed35df2011-11-02 13:06:18 +01001671 pdp->gsnlc.l = sizeof(options.listen);
1672 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1673 pdp->gsnlu.l = sizeof(options.listen);
1674 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001675
Harald Weltebed35df2011-11-02 13:06:18 +01001676 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001677 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001678 "MSISDN length too big");
1679 exit(1);
1680 } else {
1681 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1682 }
jjakob62c3dd2004-05-27 18:51:55 +00001683
Harald Welte840a8e92017-09-24 18:12:40 +08001684 /* Request dynamic IP address */
1685 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1686 pdp->eua.v[1] = options.pdp_type;
1687 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001688
Harald Weltebed35df2011-11-02 13:06:18 +01001689 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001690 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001691 "PCO length too big");
1692 exit(1);
1693 } else {
1694 pdp->pco_req.l = options.pco.l;
1695 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1696 }
jjako52c24142002-12-16 13:33:51 +00001697
Harald Weltebed35df2011-11-02 13:06:18 +01001698 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001699
Harald Weltebed35df2011-11-02 13:06:18 +01001700 pdp->hisaddr0 = options.remote;
1701 pdp->hisaddr1 = options.remote;
1702
1703 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1704 512 = Flat rate, 256 = Hot billing */
1705
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001706 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1707
Harald Weltebed35df2011-11-02 13:06:18 +01001708 /* Create context */
1709 /* We send this of once. Retransmissions are handled by gtplib */
1710 gtp_create_context_req(gsn, pdp, &iparr[n]);
1711 }
1712
1713 state = 1; /* Enter wait_connection state */
1714
1715 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001716
jjako52c24142002-12-16 13:33:51 +00001717 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001718 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001719 /******************************************************************/
1720
Harald Weltebed35df2011-11-02 13:06:18 +01001721 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001722
Harald Weltebed35df2011-11-02 13:06:18 +01001723 /* Take down client after timeout after disconnect */
1724 if ((4 == state) && ((stoptime) <= time(NULL))) {
1725 state = 5;
1726 }
jjako7b8fad42003-07-07 14:37:42 +00001727
Harald Weltebed35df2011-11-02 13:06:18 +01001728 /* Take down client after timelimit timeout */
1729 if ((2 == state) && (options.timelimit) &&
1730 ((starttime + options.timelimit) <= time(NULL))) {
1731 state = 3;
1732 }
jjako7b8fad42003-07-07 14:37:42 +00001733
Harald Weltebed35df2011-11-02 13:06:18 +01001734 /* Take down client after ping timeout */
1735 if ((2 == state) && (pingtimeout)
1736 && (pingtimeout <= time(NULL))) {
1737 state = 3;
1738 }
jjako7b8fad42003-07-07 14:37:42 +00001739
Harald Weltebed35df2011-11-02 13:06:18 +01001740 /* Set pingtimeout for later disconnection */
1741 if (options.pingcount && ntransmitted >= options.pingcount) {
1742 pingtimeout = time(NULL) + 5; /* Extra seconds */
1743 }
jjako7b8fad42003-07-07 14:37:42 +00001744
Harald Weltebed35df2011-11-02 13:06:18 +01001745 /* Print statistics if no more ping packets are missing */
1746 if (ntransmitted && options.pingcount
1747 && nreceived >= options.pingcount) {
1748 ping_finish();
1749 if (!options.createif)
1750 state = 3;
1751 }
jjako7b8fad42003-07-07 14:37:42 +00001752
Harald Weltebed35df2011-11-02 13:06:18 +01001753 /* Send off disconnect */
1754 if (3 == state) {
1755 state = 4;
1756 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1757 for (n = 0; n < options.contexts; n++) {
1758 /* Delete context */
1759 printf("Disconnecting PDP context #%d\n", n);
1760 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1761 1);
1762 if ((options.pinghost.s_addr != 0)
1763 && ntransmitted)
1764 ping_finish();
1765 }
1766 }
jjako7b8fad42003-07-07 14:37:42 +00001767
Harald Weltebed35df2011-11-02 13:06:18 +01001768 /* Send of ping packets */
1769 diff = 0;
1770 while ((diff <= 0) &&
1771 /* Send off an ICMP ping packet */
1772 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1773 ((pingseq < options.pingcount)
1774 || (options.pingcount == 0))) {
1775 if (!pingseq)
1776 gettimeofday(&firstping, &tz); /* Set time of first ping */
1777 gettimeofday(&tv, &tz);
1778 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1779 if (diff <= 0) {
1780 if (options.debug)
1781 printf("Create_ping %d\n", diff);
1782 create_ping(gsn,
1783 iparr[pingseq %
1784 options.contexts].pdp,
1785 &options.pinghost, pingseq,
1786 options.pingsize);
1787 pingseq++;
1788 }
1789 }
jjako5da68452003-01-28 16:08:47 +00001790
Harald Weltebed35df2011-11-02 13:06:18 +01001791 FD_ZERO(&fds);
1792 if (tun)
1793 FD_SET(tun->fd, &fds);
1794 FD_SET(gsn->fd0, &fds);
1795 FD_SET(gsn->fd1c, &fds);
1796 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001797
Harald Weltebed35df2011-11-02 13:06:18 +01001798 gtp_retranstimeout(gsn, &idleTime);
1799 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001800
Harald Weltebed35df2011-11-02 13:06:18 +01001801 if (options.debug)
1802 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1803 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001804
bjovana8f71eb2017-02-24 17:39:20 +01001805 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001806 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1807 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001808 if (errno == EINTR)
1809 signal_received = 1;
1810 else
1811 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1812 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001813 break;
1814 case 0:
1815 gtp_retrans(gsn); /* Only retransmit if nothing else */
1816 break;
1817 default:
1818 break;
1819 }
1820
bjovana8f71eb2017-02-24 17:39:20 +01001821 if (!signal_received) {
1822
1823 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1824 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1825 "TUN decaps failed");
1826 }
1827
1828 if (FD_ISSET(gsn->fd0, &fds))
1829 gtp_decaps0(gsn);
1830
1831 if (FD_ISSET(gsn->fd1c, &fds))
1832 gtp_decaps1c(gsn);
1833
1834 if (FD_ISSET(gsn->fd1u, &fds))
1835 gtp_decaps1u(gsn);
1836
Harald Weltebed35df2011-11-02 13:06:18 +01001837 }
Harald Weltebed35df2011-11-02 13:06:18 +01001838 }
1839
1840 gtp_free(gsn); /* Clean up the gsn instance */
1841
1842 if (options.createif)
1843 tun_free(tun);
1844
1845 if (0 == state)
1846 exit(1); /* Indicate error */
1847
1848 return 0;
jjako52c24142002-12-16 13:33:51 +00001849}