blob: 50eca6392b879bd5c41f7255e238f626314daa39 [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)
352 printf("tun-device: %d\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 }
977 return ret;
978
979out:
980 fclose(f);
981 return ret;
982}
983
984/* Read value of a /proc/sys/net/ipv6/conf file for given device.
985 * Memory is dynamically allocated, caller must free it later. */
986static char *proc_ipv6_conf_read(const char *dev, const char *file)
987{
988 const char *fmt = "/proc/sys/net/ipv6/conf/%s/%s";
989 char path[strlen(fmt) + strlen(dev) + strlen(file)];
990 snprintf(path, sizeof(path), fmt, dev, file);
991 return proc_read(path);
992}
993
Harald Weltefed33892017-10-10 09:02:45 +0800994static char *print_ipprot(int t)
Harald Weltebed35df2011-11-02 13:06:18 +0100995{
996 switch (t) {
997 case 1:
998 return "ICMP";
999 case 6:
1000 return "TCP";
1001 case 17:
1002 return "UDP";
1003 default:
1004 return "Unknown";
1005 };
jjako5da68452003-01-28 16:08:47 +00001006}
1007
Harald Weltefed33892017-10-10 09:02:45 +08001008static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001009{
1010 static char *ttab[] = {
1011 "Echo Reply",
1012 "ICMP 1",
1013 "ICMP 2",
1014 "Dest Unreachable",
1015 "Source Quench",
1016 "Redirect",
1017 "ICMP 6",
1018 "ICMP 7",
1019 "Echo",
1020 "ICMP 9",
1021 "ICMP 10",
1022 "Time Exceeded",
1023 "Parameter Problem",
1024 "Timestamp",
1025 "Timestamp Reply",
1026 "Info Request",
1027 "Info Reply"
1028 };
1029 if (t < 0 || t > 16)
1030 return ("OUT-OF-RANGE");
1031 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001032}
1033
Harald Weltefed33892017-10-10 09:02:45 +08001034static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001035{
1036 unsigned int n;
1037 uint64_t i64 = 0;
1038 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1039 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001040
Harald Weltebed35df2011-11-02 13:06:18 +01001041 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1042 /* ul16_t format always starts with 0x91 to indicate international format */
1043 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1044 for (n = 0; n < src->l; n++) {
1045 if ((src->v[n] & 0x0f) != 0x0f) {
1046 i64 *= 10;
1047 i64 += src->v[n] & 0x0f;
1048 }
1049 if ((src->v[n] & 0xf0) != 0xf0) {
1050 i64 *= 10;
1051 i64 += (src->v[n] & 0xf0) >> 4;
1052 }
1053 }
jjako193e8b12003-11-10 12:31:41 +00001054
Harald Weltebed35df2011-11-02 13:06:18 +01001055 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001056
Harald Weltebed35df2011-11-02 13:06:18 +01001057 /* Generate array with least significant digit in first octet */
1058 while (i64) {
1059 msa[msalen++] = i64 % 10;
1060 i64 = i64 / 10;
1061 }
jjako193e8b12003-11-10 12:31:41 +00001062
Harald Weltebed35df2011-11-02 13:06:18 +01001063 /* Convert back to ul16_t format */
1064 for (n = 0; n < msalen; n++) {
1065 if ((n % 2) == 0) {
1066 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1067 dst->l += 1;
1068 } else {
1069 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1070 msa[msalen - n - 1] * 16;
1071 }
1072 }
jjako193e8b12003-11-10 12:31:41 +00001073
Harald Weltebed35df2011-11-02 13:06:18 +01001074 return 0;
jjako193e8b12003-11-10 12:31:41 +00001075
1076}
1077
Harald Weltefed33892017-10-10 09:02:45 +08001078static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001079{
1080 /* TODO: big endian / small endian ??? */
1081 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001082
Harald Weltebed35df2011-11-02 13:06:18 +01001083 /* Convert from uint64_t bcd to uint64_t integer format */
1084 /* The resulting integer format is multiplied by 10 */
1085 while (src) {
1086 if ((src & 0x0f) != 0x0f) {
1087 i64 *= 10;
1088 i64 += (src & 0x0f);
1089 }
1090 if ((src & 0xf0) != 0xf0) {
1091 i64 *= 10;
1092 i64 += (src & 0xf0) >> 4;
1093 }
1094 src = src >> 8;
1095 }
jjako193e8b12003-11-10 12:31:41 +00001096
Harald Weltebed35df2011-11-02 13:06:18 +01001097 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001098
Harald Weltebed35df2011-11-02 13:06:18 +01001099 *dst = 0;
1100 while (i64) {
1101 *dst = *dst << 4;
1102 *dst += (i64 % 10);
1103 i64 = i64 / 10;
1104 }
jjako193e8b12003-11-10 12:31:41 +00001105
Harald Weltebed35df2011-11-02 13:06:18 +01001106 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001107
Harald Weltebed35df2011-11-02 13:06:18 +01001108 return 0;
jjako193e8b12003-11-10 12:31:41 +00001109
1110}
1111
jjakoafb2a972003-01-29 21:04:13 +00001112/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001113static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001114{
1115 struct timezone tz;
1116 struct timeval tv;
1117 int diff;
1118 if ((options.pinghost.s_addr) && (2 == state) &&
1119 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1120 gettimeofday(&tv, &tz);
1121 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1122 tp->tv_sec = 0;
1123 if (diff > 0)
1124 tp->tv_usec = diff;
1125 else {
1126 /* For some reason we get packet loss if set to zero */
1127 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1128 tp->tv_usec = 0;
1129 }
1130 }
1131 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001132}
1133
jjako5da68452003-01-28 16:08:47 +00001134/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001135static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001136{
Harald Weltebed35df2011-11-02 13:06:18 +01001137 struct timezone tz;
1138 struct timeval tv;
1139 int elapsed;
1140 gettimeofday(&tv, &tz);
1141 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1142 printf("\n");
1143 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1144 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1145 elapsed / 1000000.0);
1146 printf("%d packets received, ", nreceived);
1147 if (ntransmitted) {
1148 if (nreceived > ntransmitted)
1149 printf("-- somebody's printing up packets!");
1150 else
1151 printf("%d%% packet loss",
1152 (int)(((ntransmitted - nreceived) * 100) /
1153 ntransmitted));
1154 }
1155 printf("\n");
1156 if (options.debug)
1157 printf("%d packets received in total\n", ntreceived);
1158 if (nreceived && tsum)
1159 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1160 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1161 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001162
Harald Weltebed35df2011-11-02 13:06:18 +01001163 ntransmitted = 0;
1164 return 0;
jjako5da68452003-01-28 16:08:47 +00001165}
1166
1167/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltefed33892017-10-10 09:02:45 +08001168static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001169{
1170 struct timezone tz;
1171 struct timeval tv;
1172 struct timeval *tp;
1173 struct ip_ping *pingpack = pack;
1174 struct in_addr src;
1175 int triptime;
jjako5da68452003-01-28 16:08:47 +00001176
Harald Weltebed35df2011-11-02 13:06:18 +01001177 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001178
Harald Weltebed35df2011-11-02 13:06:18 +01001179 gettimeofday(&tv, &tz);
1180 if (options.debug)
1181 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001182
Harald Weltebed35df2011-11-02 13:06:18 +01001183 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1184 printf("packet too short (%d bytes) from %s\n", len,
1185 inet_ntoa(src));
1186 return 0;
1187 }
jjako5da68452003-01-28 16:08:47 +00001188
Harald Weltebed35df2011-11-02 13:06:18 +01001189 ntreceived++;
1190 if (pingpack->protocol != 1) {
1191 if (!options.pingquiet)
1192 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1193 len, inet_ntoa(src), pingpack->protocol,
1194 print_ipprot(pingpack->protocol));
1195 return 0;
1196 }
jjako5da68452003-01-28 16:08:47 +00001197
Harald Weltebed35df2011-11-02 13:06:18 +01001198 if (pingpack->type != 0) {
1199 if (!options.pingquiet)
1200 printf
1201 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1202 len, inet_ntoa(src), pingpack->type,
1203 print_icmptype(pingpack->type), pingpack->code);
1204 return 0;
1205 }
jjako5da68452003-01-28 16:08:47 +00001206
Harald Weltebed35df2011-11-02 13:06:18 +01001207 nreceived++;
1208 if (!options.pingquiet)
1209 printf("%d bytes from %s: icmp_seq=%d", len,
1210 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001211
Harald Weltebed35df2011-11-02 13:06:18 +01001212 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1213 gettimeofday(&tv, &tz);
1214 tp = (struct timeval *)pingpack->data;
1215 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1216 tv.tv_sec--;
1217 tv.tv_usec += 1000000;
1218 }
1219 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001220
Harald Weltebed35df2011-11-02 13:06:18 +01001221 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1222 tsum += triptime;
1223 if (triptime < tmin)
1224 tmin = triptime;
1225 if (triptime > tmax)
1226 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001227
Harald Weltebed35df2011-11-02 13:06:18 +01001228 if (!options.pingquiet)
1229 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001230
Harald Weltebed35df2011-11-02 13:06:18 +01001231 } else if (!options.pingquiet)
1232 printf("\n");
1233 return 0;
jjako5da68452003-01-28 16:08:47 +00001234}
1235
1236/* Create a new ping packet and send it off to peer. */
Harald Weltefed33892017-10-10 09:02:45 +08001237static int create_ping(void *gsn, struct pdp_t *pdp,
1238 struct in_addr *dst, int seq, unsigned int datasize)
Harald Weltebed35df2011-11-02 13:06:18 +01001239{
jjako5da68452003-01-28 16:08:47 +00001240
Harald Weltebed35df2011-11-02 13:06:18 +01001241 struct ip_ping pack;
1242 uint16_t *p = (uint16_t *) & pack;
1243 uint8_t *p8 = (uint8_t *) & pack;
1244 struct in_addr src;
1245 unsigned int n;
1246 long int sum = 0;
1247 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001248
Harald Weltebed35df2011-11-02 13:06:18 +01001249 struct timezone tz;
1250 struct timeval *tp =
1251 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001252
Harald Weltebed35df2011-11-02 13:06:18 +01001253 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001254 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001255 "Ping size to large: %d!", datasize);
1256 return -1;
1257 }
jjako5da68452003-01-28 16:08:47 +00001258
Harald Weltebed35df2011-11-02 13:06:18 +01001259 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001260
Harald Weltebed35df2011-11-02 13:06:18 +01001261 pack.ipver = 0x45;
1262 pack.tos = 0x00;
1263 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1264 pack.fragid = 0x0000;
1265 pack.offset = 0x0040;
1266 pack.ttl = 0x40;
1267 pack.protocol = 0x01;
1268 pack.ipcheck = 0x0000;
1269 pack.src = src.s_addr;
1270 pack.dst = dst->s_addr;
1271 pack.type = 0x08;
1272 pack.code = 0x00;
1273 pack.checksum = 0x0000;
1274 pack.ident = 0x0000;
1275 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001276
Harald Weltebed35df2011-11-02 13:06:18 +01001277 /* Generate ICMP payload */
1278 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1279 for (n = 0; n < (datasize); n++)
1280 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001281
Harald Weltebed35df2011-11-02 13:06:18 +01001282 if (datasize >= sizeof(struct timeval))
1283 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001284
Harald Weltebed35df2011-11-02 13:06:18 +01001285 /* Calculate IP header checksum */
1286 p = (uint16_t *) & pack;
1287 count = CREATEPING_IP;
1288 sum = 0;
1289 while (count > 1) {
1290 sum += *p++;
1291 count -= 2;
1292 }
1293 while (sum >> 16)
1294 sum = (sum & 0xffff) + (sum >> 16);
1295 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001296
Harald Weltebed35df2011-11-02 13:06:18 +01001297 /* Calculate ICMP checksum */
1298 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1299 sum = 0;
1300 p = (uint16_t *) & pack;
1301 p += CREATEPING_IP / 2;
1302 while (count > 1) {
1303 sum += *p++;
1304 count -= 2;
1305 }
1306 if (count > 0)
1307 sum += *(unsigned char *)p;
1308 while (sum >> 16)
1309 sum = (sum & 0xffff) + (sum >> 16);
1310 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001311
Harald Weltebed35df2011-11-02 13:06:18 +01001312 ntransmitted++;
1313 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001314}
1315
Harald Weltefed33892017-10-10 09:02:45 +08001316static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001317{
1318
1319 if (tun && options.ipdown)
1320 tun_runscript(tun, options.ipdown);
1321
1322 ipdel((struct iphash_t *)pdp->peer);
1323 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1324
1325 if (1 == options.contexts)
1326 state = 5; /* Disconnected */
1327
1328 return 0;
1329}
jjakoa7cd2492003-04-11 09:40:12 +00001330
Harald Welte6748dc92017-09-24 21:54:59 +08001331/* Link-Local address prefix fe80::/64 */
1332static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1333
jjakoa7cd2492003-04-11 09:40:12 +00001334/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001335static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001336{
1337 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001338 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001339 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001340 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001341
Harald Welte6748dc92017-09-24 21:54:59 +08001342 if (iph->version == 4) {
1343 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1344 printf("Dropping packet with too short IP header\n");
1345 return 0;
1346 }
1347 src.len = 4;
1348 src.v4.s_addr = iph->saddr;
1349 } else if (iph->version == 6) {
1350 /* We only have a single entry in the hash table, and it consists of the link-local
1351 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1352 * addresses to that format before looking up the hash table via ippool_getip() */
1353 src.len = 16;
1354 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1355 /* is a link-local address, we can do the hash lookup 1:1 */
1356 src.v6 = ip6h->ip6_src;
1357 } else {
1358 /* it is not a link-local address, so we must convert from the /64 prefix
1359 * to the link-local format that's used in the hash table */
1360 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1361 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1362 }
1363 } else {
1364 printf("Dropping packet with invalid IP version %u\n", iph->version);
1365 return 0;
1366 }
jjakoa7cd2492003-04-11 09:40:12 +00001367
Harald Weltebed35df2011-11-02 13:06:18 +01001368 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001369 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001370 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001371 return 0;
1372 }
1373
1374 if (ipm->pdp) /* Check if a peer protocol is defined */
1375 gtp_data_req(gsn, ipm->pdp, pack, len);
1376 return 0;
jjako52c24142002-12-16 13:33:51 +00001377}
1378
Harald Weltefed33892017-10-10 09:02:45 +08001379static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001380{
Harald Welted12eab92017-08-02 19:49:47 +02001381 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001382
Harald Weltebed35df2011-11-02 13:06:18 +01001383 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001384
Harald Weltebed35df2011-11-02 13:06:18 +01001385 if (cause < 0) {
1386 printf("Create PDP Context Request timed out\n");
1387 if (iph->pdp->version == 1) {
1388 printf("Retrying with version 0\n");
1389 iph->pdp->version = 0;
1390 gtp_create_context_req(gsn, iph->pdp, iph);
1391 return 0;
1392 } else {
1393 state = 0;
1394 pdp_freepdp(iph->pdp);
1395 iph->pdp = NULL;
1396 return EOF;
1397 }
1398 }
jjako2c381332003-10-21 19:09:53 +00001399
Harald Weltebed35df2011-11-02 13:06:18 +01001400 if (cause != 128) {
1401 printf
1402 ("Received create PDP context response. Cause value: %d\n",
1403 cause);
1404 state = 0;
1405 pdp_freepdp(iph->pdp);
1406 iph->pdp = NULL;
1407 return EOF; /* Not what we expected */
1408 }
jjako52c24142002-12-16 13:33:51 +00001409
Harald Weltea0d281d2017-08-02 21:48:16 +02001410 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001411 printf
1412 ("Received create PDP context response. Cause value: %d\n",
1413 cause);
1414 pdp_freepdp(iph->pdp);
1415 iph->pdp = NULL;
1416 state = 0;
1417 return EOF; /* Not a valid IP address */
1418 }
jjakoa7cd2492003-04-11 09:40:12 +00001419
Harald Weltebed35df2011-11-02 13:06:18 +01001420 printf("Received create PDP context response. IP address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001421 in46a_ntoa(&addr));
1422
1423 switch (addr.len) {
1424 case 16: /* IPv6 */
1425 /* we have to enable the kernel to perform stateless autoconfiguration,
1426 * i.e. send a router solicitation using the lover 64bits of the allocated
1427 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1428 memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1429 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
1430 break;
1431 case 4: /* IPv4 */
1432 break;
1433 }
jjakoa7cd2492003-04-11 09:40:12 +00001434
Harald Weltebed35df2011-11-02 13:06:18 +01001435 if ((options.createif) && (!options.net.s_addr)) {
Harald Welte6748dc92017-09-24 21:54:59 +08001436 size_t prefixlen = 32;
1437 if (addr.len == 16)
1438 prefixlen = 64;
Harald Weltebed35df2011-11-02 13:06:18 +01001439 /* printf("Setting up interface and routing\n"); */
Harald Welte6748dc92017-09-24 21:54:59 +08001440 /* FIXME: use tun_addattr() not tun_setaddr() */
1441 tun_setaddr(tun, &addr, &addr, prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001442 if (options.defaultroute) {
1443 struct in_addr rm;
1444 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001445 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001446 }
1447 if (options.ipup)
1448 tun_runscript(tun, options.ipup);
1449 }
jjako52c24142002-12-16 13:33:51 +00001450
Harald Welte081f30c2017-10-10 09:36:35 +08001451 /* now that ip-up has been executed, check if we are configured to
1452 * accept router advertisements */
1453 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
1454 char *accept_ra, *forwarding;
1455
1456 accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
1457 forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
1458 if (!accept_ra || !forwarding)
1459 printf("Could not open proc file for %s ?!?\n", tun->devname);
1460 else {
1461 if (!strcmp(accept_ra, "0") ||
1462 (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1"))) {
1463 printf("%s is %s, i.e. your tun device is not configured to accept "
1464 "router advertisements; SLAAC will not suceed, please "
1465 "fix your setup!\n");
1466 }
1467 free(accept_ra);
1468 free(forwarding);
1469 }
1470 }
1471
Harald Weltebed35df2011-11-02 13:06:18 +01001472 ipset((struct iphash_t *)pdp->peer, &addr);
1473
1474 state = 2; /* Connected */
1475
1476 return 0;
jjako52c24142002-12-16 13:33:51 +00001477}
1478
Harald Weltefed33892017-10-10 09:02:45 +08001479static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001480{
1481 printf("Received delete PDP context response. Cause value: %d\n",
1482 cause);
1483 return 0;
jjako52c24142002-12-16 13:33:51 +00001484}
1485
Harald Weltefed33892017-10-10 09:02:45 +08001486static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001487{
jjako91aaf222003-10-22 10:09:32 +00001488
Harald Weltebed35df2011-11-02 13:06:18 +01001489 if (recovery < 0) {
1490 printf("Echo Request timed out\n");
1491 if (echoversion == 1) {
1492 printf("Retrying with version 0\n");
1493 echoversion = 0;
1494 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1495 return 0;
1496 } else {
1497 state = 0;
1498 return EOF;
1499 }
1500 } else {
1501 printf("Received echo response\n");
1502 if (!options.contexts)
1503 state = 5;
1504 }
1505 return 0;
jjako52c24142002-12-16 13:33:51 +00001506}
1507
Harald Weltefed33892017-10-10 09:02:45 +08001508static int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001509{
1510 /* if (cause < 0) return 0; Some error occurred. We don't care */
1511 switch (type) {
1512 case GTP_ECHO_REQ:
1513 return echo_conf(cause);
1514 case GTP_CREATE_PDP_REQ:
1515 return create_pdp_conf(pdp, cbp, cause);
1516 case GTP_DELETE_PDP_REQ:
1517 if (cause != 128)
1518 return 0; /* Request not accepted. We don't care */
1519 return delete_pdp_conf(pdp, cause);
1520 default:
1521 return 0;
1522 }
jjako52c24142002-12-16 13:33:51 +00001523}
1524
Harald Weltefed33892017-10-10 09:02:45 +08001525static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001526{
1527 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1528 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001529}
1530
1531int main(int argc, char **argv)
1532{
Harald Weltebed35df2011-11-02 13:06:18 +01001533 fd_set fds; /* For select() */
1534 struct timeval idleTime; /* How long to select() */
1535 struct pdp_t *pdp;
1536 int n;
1537 int starttime = time(NULL); /* Time program was started */
1538 int stoptime = 0; /* Time to exit */
1539 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001540 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001541
Harald Weltebed35df2011-11-02 13:06:18 +01001542 struct timezone tz; /* Used for calculating ping times */
1543 struct timeval tv;
1544 int diff;
jjako52c24142002-12-16 13:33:51 +00001545
bjovana8f71eb2017-02-24 17:39:20 +01001546 signal(SIGTERM, signal_handler);
1547 signal(SIGHUP, signal_handler);
1548 signal(SIGINT, signal_handler);
1549
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001550 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 /* Process options given in configuration file and command line */
1553 if (process_options(argc, argv))
1554 exit(1);
jjako52c24142002-12-16 13:33:51 +00001555
Harald Weltebed35df2011-11-02 13:06:18 +01001556 printf("\nInitialising GTP library\n");
1557 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001558 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001559 exit(1);
1560 }
1561 if (gsn->fd0 > maxfd)
1562 maxfd = gsn->fd0;
1563 if (gsn->fd1c > maxfd)
1564 maxfd = gsn->fd1c;
1565 if (gsn->fd1u > maxfd)
1566 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001567
Harald Weltebed35df2011-11-02 13:06:18 +01001568 gtp_set_cb_delete_context(gsn, delete_context);
1569 gtp_set_cb_conf(gsn, conf);
1570 if (options.createif)
1571 gtp_set_cb_data_ind(gsn, encaps_tun);
1572 else
1573 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001574
Harald Weltebed35df2011-11-02 13:06:18 +01001575 if (options.createif) {
1576 printf("Setting up interface\n");
1577 /* Create a tunnel interface */
Harald Welte73abc382017-10-10 08:50:11 +08001578 if (tun_new((struct tun_t **)&tun, options.tun_dev_name)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001579 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001580 "Failed to create tun");
1581 exit(1);
1582 }
1583 tun_set_cb_ind(tun, cb_tun_ind);
1584 if (tun->fd > maxfd)
1585 maxfd = tun->fd;
1586 }
jjakoa7cd2492003-04-11 09:40:12 +00001587
Harald Weltebed35df2011-11-02 13:06:18 +01001588 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001589 struct in_addr mask;
1590 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001591 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001592 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001593 if (options.defaultroute) {
1594 struct in_addr rm;
1595 rm.s_addr = 0;
1596 tun_addroute(tun, &rm, &options.destaddr, &rm);
1597 }
1598 if (options.ipup)
1599 tun_runscript(tun, options.ipup);
1600 }
jjakoa7cd2492003-04-11 09:40:12 +00001601
Harald Weltebed35df2011-11-02 13:06:18 +01001602 /* Initialise hash tables */
1603 memset(&iphash, 0, sizeof(iphash));
1604 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001605
Harald Weltebed35df2011-11-02 13:06:18 +01001606 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001607
Harald Weltebed35df2011-11-02 13:06:18 +01001608 /* See if anybody is there */
1609 printf("Sending off echo request\n");
1610 echoversion = options.gtpversion;
1611 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001612
Harald Weltebed35df2011-11-02 13:06:18 +01001613 for (n = 0; n < options.contexts; n++) {
1614 uint64_t myimsi;
1615 printf("Setting up PDP context #%d\n", n);
1616 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001617
Harald Weltebed35df2011-11-02 13:06:18 +01001618 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001619
Harald Weltebed35df2011-11-02 13:06:18 +01001620 /* Allocated here. */
1621 /* If create context failes we have to deallocate ourselves. */
1622 /* Otherwise it is deallocated by gtplib */
1623 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001624
Harald Weltebed35df2011-11-02 13:06:18 +01001625 pdp->peer = &iparr[n];
1626 pdp->ipif = tun; /* TODO */
1627 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001628
Harald Weltebed35df2011-11-02 13:06:18 +01001629 if (options.gtpversion == 0) {
1630 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001631 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001632 "QoS length too big");
1633 exit(1);
1634 } else {
1635 memcpy(pdp->qos_req0, options.qos.v,
1636 options.qos.l);
1637 }
1638 }
jjakoa7cd2492003-04-11 09:40:12 +00001639
Harald Weltebed35df2011-11-02 13:06:18 +01001640 pdp->qos_req.l = options.qos.l;
1641 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001642
Harald Weltebed35df2011-11-02 13:06:18 +01001643 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001644
Harald Weltebed35df2011-11-02 13:06:18 +01001645 pdp->rattype.l = options.rattype.l;
1646 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1647 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001648
Harald Weltebed35df2011-11-02 13:06:18 +01001649 pdp->userloc.l = options.userloc.l;
1650 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1651 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001652
Harald Weltebed35df2011-11-02 13:06:18 +01001653 pdp->rai.l = options.rai.l;
1654 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1655 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001656
Harald Weltebed35df2011-11-02 13:06:18 +01001657 pdp->mstz.l = options.mstz.l;
1658 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1659 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001660
Harald Weltebed35df2011-11-02 13:06:18 +01001661 pdp->imeisv.l = options.imeisv.l;
1662 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1663 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001664
Harald Weltebed35df2011-11-02 13:06:18 +01001665 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001666
Harald Weltebed35df2011-11-02 13:06:18 +01001667 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001668 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001669 "APN length too big");
1670 exit(1);
1671 } else {
1672 pdp->apn_use.l = options.apn.l;
1673 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1674 }
jjako193e8b12003-11-10 12:31:41 +00001675
Harald Weltebed35df2011-11-02 13:06:18 +01001676 pdp->gsnlc.l = sizeof(options.listen);
1677 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1678 pdp->gsnlu.l = sizeof(options.listen);
1679 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001680
Harald Weltebed35df2011-11-02 13:06:18 +01001681 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001682 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001683 "MSISDN length too big");
1684 exit(1);
1685 } else {
1686 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1687 }
jjakob62c3dd2004-05-27 18:51:55 +00001688
Harald Welte840a8e92017-09-24 18:12:40 +08001689 /* Request dynamic IP address */
1690 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1691 pdp->eua.v[1] = options.pdp_type;
1692 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001693
Harald Weltebed35df2011-11-02 13:06:18 +01001694 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001695 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001696 "PCO length too big");
1697 exit(1);
1698 } else {
1699 pdp->pco_req.l = options.pco.l;
1700 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1701 }
jjako52c24142002-12-16 13:33:51 +00001702
Harald Weltebed35df2011-11-02 13:06:18 +01001703 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001704
Harald Weltebed35df2011-11-02 13:06:18 +01001705 pdp->hisaddr0 = options.remote;
1706 pdp->hisaddr1 = options.remote;
1707
1708 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1709 512 = Flat rate, 256 = Hot billing */
1710
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001711 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1712
Harald Weltebed35df2011-11-02 13:06:18 +01001713 /* Create context */
1714 /* We send this of once. Retransmissions are handled by gtplib */
1715 gtp_create_context_req(gsn, pdp, &iparr[n]);
1716 }
1717
1718 state = 1; /* Enter wait_connection state */
1719
1720 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001721
jjako52c24142002-12-16 13:33:51 +00001722 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001723 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001724 /******************************************************************/
1725
Harald Weltebed35df2011-11-02 13:06:18 +01001726 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001727
Harald Weltebed35df2011-11-02 13:06:18 +01001728 /* Take down client after timeout after disconnect */
1729 if ((4 == state) && ((stoptime) <= time(NULL))) {
1730 state = 5;
1731 }
jjako7b8fad42003-07-07 14:37:42 +00001732
Harald Weltebed35df2011-11-02 13:06:18 +01001733 /* Take down client after timelimit timeout */
1734 if ((2 == state) && (options.timelimit) &&
1735 ((starttime + options.timelimit) <= time(NULL))) {
1736 state = 3;
1737 }
jjako7b8fad42003-07-07 14:37:42 +00001738
Harald Weltebed35df2011-11-02 13:06:18 +01001739 /* Take down client after ping timeout */
1740 if ((2 == state) && (pingtimeout)
1741 && (pingtimeout <= time(NULL))) {
1742 state = 3;
1743 }
jjako7b8fad42003-07-07 14:37:42 +00001744
Harald Weltebed35df2011-11-02 13:06:18 +01001745 /* Set pingtimeout for later disconnection */
1746 if (options.pingcount && ntransmitted >= options.pingcount) {
1747 pingtimeout = time(NULL) + 5; /* Extra seconds */
1748 }
jjako7b8fad42003-07-07 14:37:42 +00001749
Harald Weltebed35df2011-11-02 13:06:18 +01001750 /* Print statistics if no more ping packets are missing */
1751 if (ntransmitted && options.pingcount
1752 && nreceived >= options.pingcount) {
1753 ping_finish();
1754 if (!options.createif)
1755 state = 3;
1756 }
jjako7b8fad42003-07-07 14:37:42 +00001757
Harald Weltebed35df2011-11-02 13:06:18 +01001758 /* Send off disconnect */
1759 if (3 == state) {
1760 state = 4;
1761 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1762 for (n = 0; n < options.contexts; n++) {
1763 /* Delete context */
1764 printf("Disconnecting PDP context #%d\n", n);
1765 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1766 1);
1767 if ((options.pinghost.s_addr != 0)
1768 && ntransmitted)
1769 ping_finish();
1770 }
1771 }
jjako7b8fad42003-07-07 14:37:42 +00001772
Harald Weltebed35df2011-11-02 13:06:18 +01001773 /* Send of ping packets */
1774 diff = 0;
1775 while ((diff <= 0) &&
1776 /* Send off an ICMP ping packet */
1777 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1778 ((pingseq < options.pingcount)
1779 || (options.pingcount == 0))) {
1780 if (!pingseq)
1781 gettimeofday(&firstping, &tz); /* Set time of first ping */
1782 gettimeofday(&tv, &tz);
1783 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1784 if (diff <= 0) {
1785 if (options.debug)
1786 printf("Create_ping %d\n", diff);
1787 create_ping(gsn,
1788 iparr[pingseq %
1789 options.contexts].pdp,
1790 &options.pinghost, pingseq,
1791 options.pingsize);
1792 pingseq++;
1793 }
1794 }
jjako5da68452003-01-28 16:08:47 +00001795
Harald Weltebed35df2011-11-02 13:06:18 +01001796 FD_ZERO(&fds);
1797 if (tun)
1798 FD_SET(tun->fd, &fds);
1799 FD_SET(gsn->fd0, &fds);
1800 FD_SET(gsn->fd1c, &fds);
1801 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001802
Harald Weltebed35df2011-11-02 13:06:18 +01001803 gtp_retranstimeout(gsn, &idleTime);
1804 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001805
Harald Weltebed35df2011-11-02 13:06:18 +01001806 if (options.debug)
1807 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1808 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001809
bjovana8f71eb2017-02-24 17:39:20 +01001810 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001811 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1812 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001813 if (errno == EINTR)
1814 signal_received = 1;
1815 else
1816 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1817 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001818 break;
1819 case 0:
1820 gtp_retrans(gsn); /* Only retransmit if nothing else */
1821 break;
1822 default:
1823 break;
1824 }
1825
bjovana8f71eb2017-02-24 17:39:20 +01001826 if (!signal_received) {
1827
1828 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1829 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1830 "TUN decaps failed");
1831 }
1832
1833 if (FD_ISSET(gsn->fd0, &fds))
1834 gtp_decaps0(gsn);
1835
1836 if (FD_ISSET(gsn->fd1c, &fds))
1837 gtp_decaps1c(gsn);
1838
1839 if (FD_ISSET(gsn->fd1u, &fds))
1840 gtp_decaps1u(gsn);
1841
Harald Weltebed35df2011-11-02 13:06:18 +01001842 }
Harald Weltebed35df2011-11-02 13:06:18 +01001843 }
1844
1845 gtp_free(gsn); /* Clean up the gsn instance */
1846
1847 if (options.createif)
1848 tun_free(tun);
1849
1850 if (0 == state)
1851 exit(1); /* Indicate error */
1852
1853 return 0;
jjako52c24142002-12-16 13:33:51 +00001854}