blob: 23cf2086abeca7287043a51d80a113286ca80769 [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{
Harald Weltee37f48e2017-10-10 09:05:50 +0800996 struct protoent *pe = getprotobynumber(t);
997
998 if (!pe)
Harald Weltebed35df2011-11-02 13:06:18 +0100999 return "Unknown";
Harald Weltee37f48e2017-10-10 09:05:50 +08001000 else
1001 return pe->p_name;
jjako5da68452003-01-28 16:08:47 +00001002}
1003
Harald Weltefed33892017-10-10 09:02:45 +08001004static char *print_icmptype(int t)
Harald Weltebed35df2011-11-02 13:06:18 +01001005{
1006 static char *ttab[] = {
1007 "Echo Reply",
1008 "ICMP 1",
1009 "ICMP 2",
1010 "Dest Unreachable",
1011 "Source Quench",
1012 "Redirect",
1013 "ICMP 6",
1014 "ICMP 7",
1015 "Echo",
1016 "ICMP 9",
1017 "ICMP 10",
1018 "Time Exceeded",
1019 "Parameter Problem",
1020 "Timestamp",
1021 "Timestamp Reply",
1022 "Info Request",
1023 "Info Reply"
1024 };
1025 if (t < 0 || t > 16)
1026 return ("OUT-OF-RANGE");
1027 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +00001028}
1029
Harald Weltefed33892017-10-10 09:02:45 +08001030static int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001031{
1032 unsigned int n;
1033 uint64_t i64 = 0;
1034 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
1035 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +00001036
Harald Weltebed35df2011-11-02 13:06:18 +01001037 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1038 /* ul16_t format always starts with 0x91 to indicate international format */
1039 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1040 for (n = 0; n < src->l; n++) {
1041 if ((src->v[n] & 0x0f) != 0x0f) {
1042 i64 *= 10;
1043 i64 += src->v[n] & 0x0f;
1044 }
1045 if ((src->v[n] & 0xf0) != 0xf0) {
1046 i64 *= 10;
1047 i64 += (src->v[n] & 0xf0) >> 4;
1048 }
1049 }
jjako193e8b12003-11-10 12:31:41 +00001050
Harald Weltebed35df2011-11-02 13:06:18 +01001051 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001052
Harald Weltebed35df2011-11-02 13:06:18 +01001053 /* Generate array with least significant digit in first octet */
1054 while (i64) {
1055 msa[msalen++] = i64 % 10;
1056 i64 = i64 / 10;
1057 }
jjako193e8b12003-11-10 12:31:41 +00001058
Harald Weltebed35df2011-11-02 13:06:18 +01001059 /* Convert back to ul16_t format */
1060 for (n = 0; n < msalen; n++) {
1061 if ((n % 2) == 0) {
1062 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1063 dst->l += 1;
1064 } else {
1065 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1066 msa[msalen - n - 1] * 16;
1067 }
1068 }
jjako193e8b12003-11-10 12:31:41 +00001069
Harald Weltebed35df2011-11-02 13:06:18 +01001070 return 0;
jjako193e8b12003-11-10 12:31:41 +00001071
1072}
1073
Harald Weltefed33892017-10-10 09:02:45 +08001074static int imsi_add(uint64_t src, uint64_t * dst, int add)
Harald Weltebed35df2011-11-02 13:06:18 +01001075{
1076 /* TODO: big endian / small endian ??? */
1077 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001078
Harald Weltebed35df2011-11-02 13:06:18 +01001079 /* Convert from uint64_t bcd to uint64_t integer format */
1080 /* The resulting integer format is multiplied by 10 */
1081 while (src) {
1082 if ((src & 0x0f) != 0x0f) {
1083 i64 *= 10;
1084 i64 += (src & 0x0f);
1085 }
1086 if ((src & 0xf0) != 0xf0) {
1087 i64 *= 10;
1088 i64 += (src & 0xf0) >> 4;
1089 }
1090 src = src >> 8;
1091 }
jjako193e8b12003-11-10 12:31:41 +00001092
Harald Weltebed35df2011-11-02 13:06:18 +01001093 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001094
Harald Weltebed35df2011-11-02 13:06:18 +01001095 *dst = 0;
1096 while (i64) {
1097 *dst = *dst << 4;
1098 *dst += (i64 % 10);
1099 i64 = i64 / 10;
1100 }
jjako193e8b12003-11-10 12:31:41 +00001101
Harald Weltebed35df2011-11-02 13:06:18 +01001102 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001103
Harald Weltebed35df2011-11-02 13:06:18 +01001104 return 0;
jjako193e8b12003-11-10 12:31:41 +00001105
1106}
1107
jjakoafb2a972003-01-29 21:04:13 +00001108/* Calculate time left until we have to send off next ping packet */
Harald Weltefed33892017-10-10 09:02:45 +08001109static int ping_timeout(struct timeval *tp)
Harald Weltebed35df2011-11-02 13:06:18 +01001110{
1111 struct timezone tz;
1112 struct timeval tv;
1113 int diff;
1114 if ((options.pinghost.s_addr) && (2 == state) &&
1115 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1116 gettimeofday(&tv, &tz);
1117 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1118 tp->tv_sec = 0;
1119 if (diff > 0)
1120 tp->tv_usec = diff;
1121 else {
1122 /* For some reason we get packet loss if set to zero */
1123 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1124 tp->tv_usec = 0;
1125 }
1126 }
1127 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001128}
1129
jjako5da68452003-01-28 16:08:47 +00001130/* Print out statistics when at the end of ping sequence */
Harald Weltefed33892017-10-10 09:02:45 +08001131static int ping_finish()
jjako5da68452003-01-28 16:08:47 +00001132{
Harald Weltebed35df2011-11-02 13:06:18 +01001133 struct timezone tz;
1134 struct timeval tv;
1135 int elapsed;
1136 gettimeofday(&tv, &tz);
1137 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1138 printf("\n");
1139 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1140 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1141 elapsed / 1000000.0);
1142 printf("%d packets received, ", nreceived);
1143 if (ntransmitted) {
1144 if (nreceived > ntransmitted)
1145 printf("-- somebody's printing up packets!");
1146 else
1147 printf("%d%% packet loss",
1148 (int)(((ntransmitted - nreceived) * 100) /
1149 ntransmitted));
1150 }
1151 printf("\n");
1152 if (options.debug)
1153 printf("%d packets received in total\n", ntreceived);
1154 if (nreceived && tsum)
1155 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1156 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1157 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001158
Harald Weltebed35df2011-11-02 13:06:18 +01001159 ntransmitted = 0;
1160 return 0;
jjako5da68452003-01-28 16:08:47 +00001161}
1162
1163/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltefed33892017-10-10 09:02:45 +08001164static int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001165{
1166 struct timezone tz;
1167 struct timeval tv;
1168 struct timeval *tp;
1169 struct ip_ping *pingpack = pack;
1170 struct in_addr src;
1171 int triptime;
jjako5da68452003-01-28 16:08:47 +00001172
Harald Weltebed35df2011-11-02 13:06:18 +01001173 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001174
Harald Weltebed35df2011-11-02 13:06:18 +01001175 gettimeofday(&tv, &tz);
1176 if (options.debug)
1177 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001178
Harald Weltebed35df2011-11-02 13:06:18 +01001179 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1180 printf("packet too short (%d bytes) from %s\n", len,
1181 inet_ntoa(src));
1182 return 0;
1183 }
jjako5da68452003-01-28 16:08:47 +00001184
Harald Weltebed35df2011-11-02 13:06:18 +01001185 ntreceived++;
1186 if (pingpack->protocol != 1) {
1187 if (!options.pingquiet)
1188 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1189 len, inet_ntoa(src), pingpack->protocol,
1190 print_ipprot(pingpack->protocol));
1191 return 0;
1192 }
jjako5da68452003-01-28 16:08:47 +00001193
Harald Weltebed35df2011-11-02 13:06:18 +01001194 if (pingpack->type != 0) {
1195 if (!options.pingquiet)
1196 printf
1197 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1198 len, inet_ntoa(src), pingpack->type,
1199 print_icmptype(pingpack->type), pingpack->code);
1200 return 0;
1201 }
jjako5da68452003-01-28 16:08:47 +00001202
Harald Weltebed35df2011-11-02 13:06:18 +01001203 nreceived++;
1204 if (!options.pingquiet)
1205 printf("%d bytes from %s: icmp_seq=%d", len,
1206 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001207
Harald Weltebed35df2011-11-02 13:06:18 +01001208 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1209 gettimeofday(&tv, &tz);
1210 tp = (struct timeval *)pingpack->data;
1211 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1212 tv.tv_sec--;
1213 tv.tv_usec += 1000000;
1214 }
1215 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001216
Harald Weltebed35df2011-11-02 13:06:18 +01001217 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1218 tsum += triptime;
1219 if (triptime < tmin)
1220 tmin = triptime;
1221 if (triptime > tmax)
1222 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001223
Harald Weltebed35df2011-11-02 13:06:18 +01001224 if (!options.pingquiet)
1225 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001226
Harald Weltebed35df2011-11-02 13:06:18 +01001227 } else if (!options.pingquiet)
1228 printf("\n");
1229 return 0;
jjako5da68452003-01-28 16:08:47 +00001230}
1231
1232/* Create a new ping packet and send it off to peer. */
Harald Weltefed33892017-10-10 09:02:45 +08001233static int create_ping(void *gsn, struct pdp_t *pdp,
1234 struct in_addr *dst, int seq, unsigned int datasize)
Harald Weltebed35df2011-11-02 13:06:18 +01001235{
jjako5da68452003-01-28 16:08:47 +00001236
Harald Weltebed35df2011-11-02 13:06:18 +01001237 struct ip_ping pack;
1238 uint16_t *p = (uint16_t *) & pack;
1239 uint8_t *p8 = (uint8_t *) & pack;
1240 struct in_addr src;
1241 unsigned int n;
1242 long int sum = 0;
1243 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001244
Harald Weltebed35df2011-11-02 13:06:18 +01001245 struct timezone tz;
1246 struct timeval *tp =
1247 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001248
Harald Weltebed35df2011-11-02 13:06:18 +01001249 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001250 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001251 "Ping size to large: %d!", datasize);
1252 return -1;
1253 }
jjako5da68452003-01-28 16:08:47 +00001254
Harald Weltebed35df2011-11-02 13:06:18 +01001255 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001256
Harald Weltebed35df2011-11-02 13:06:18 +01001257 pack.ipver = 0x45;
1258 pack.tos = 0x00;
1259 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1260 pack.fragid = 0x0000;
1261 pack.offset = 0x0040;
1262 pack.ttl = 0x40;
1263 pack.protocol = 0x01;
1264 pack.ipcheck = 0x0000;
1265 pack.src = src.s_addr;
1266 pack.dst = dst->s_addr;
1267 pack.type = 0x08;
1268 pack.code = 0x00;
1269 pack.checksum = 0x0000;
1270 pack.ident = 0x0000;
1271 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001272
Harald Weltebed35df2011-11-02 13:06:18 +01001273 /* Generate ICMP payload */
1274 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1275 for (n = 0; n < (datasize); n++)
1276 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001277
Harald Weltebed35df2011-11-02 13:06:18 +01001278 if (datasize >= sizeof(struct timeval))
1279 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001280
Harald Weltebed35df2011-11-02 13:06:18 +01001281 /* Calculate IP header checksum */
1282 p = (uint16_t *) & pack;
1283 count = CREATEPING_IP;
1284 sum = 0;
1285 while (count > 1) {
1286 sum += *p++;
1287 count -= 2;
1288 }
1289 while (sum >> 16)
1290 sum = (sum & 0xffff) + (sum >> 16);
1291 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001292
Harald Weltebed35df2011-11-02 13:06:18 +01001293 /* Calculate ICMP checksum */
1294 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1295 sum = 0;
1296 p = (uint16_t *) & pack;
1297 p += CREATEPING_IP / 2;
1298 while (count > 1) {
1299 sum += *p++;
1300 count -= 2;
1301 }
1302 if (count > 0)
1303 sum += *(unsigned char *)p;
1304 while (sum >> 16)
1305 sum = (sum & 0xffff) + (sum >> 16);
1306 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001307
Harald Weltebed35df2011-11-02 13:06:18 +01001308 ntransmitted++;
1309 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001310}
1311
Harald Weltefed33892017-10-10 09:02:45 +08001312static int delete_context(struct pdp_t *pdp)
Harald Weltebed35df2011-11-02 13:06:18 +01001313{
1314
1315 if (tun && options.ipdown)
1316 tun_runscript(tun, options.ipdown);
1317
1318 ipdel((struct iphash_t *)pdp->peer);
1319 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1320
1321 if (1 == options.contexts)
1322 state = 5; /* Disconnected */
1323
1324 return 0;
1325}
jjakoa7cd2492003-04-11 09:40:12 +00001326
Harald Welte6748dc92017-09-24 21:54:59 +08001327/* Link-Local address prefix fe80::/64 */
1328static const uint8_t ll_prefix[] = { 0xfe,0x80, 0,0, 0,0, 0,0 };
1329
jjakoa7cd2492003-04-11 09:40:12 +00001330/* Callback for receiving messages from tun */
Harald Weltefed33892017-10-10 09:02:45 +08001331static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001332{
1333 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001334 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001335 struct iphdr *iph = (struct iphdr *)pack;
Harald Welte6748dc92017-09-24 21:54:59 +08001336 struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001337
Harald Welte6748dc92017-09-24 21:54:59 +08001338 if (iph->version == 4) {
1339 if (len < sizeof(*iph) || len < 4*iph->ihl) {
1340 printf("Dropping packet with too short IP header\n");
1341 return 0;
1342 }
1343 src.len = 4;
1344 src.v4.s_addr = iph->saddr;
1345 } else if (iph->version == 6) {
1346 /* We only have a single entry in the hash table, and it consists of the link-local
1347 * address "fe80::prefix". So we need to make sure to convert non-link-local source
1348 * addresses to that format before looking up the hash table via ippool_getip() */
1349 src.len = 16;
1350 if (!memcmp(ip6h->ip6_src.s6_addr, ll_prefix, sizeof(ll_prefix))) {
1351 /* is a link-local address, we can do the hash lookup 1:1 */
1352 src.v6 = ip6h->ip6_src;
1353 } else {
1354 /* it is not a link-local address, so we must convert from the /64 prefix
1355 * to the link-local format that's used in the hash table */
1356 memcpy(&src.v6.s6_addr[0], ll_prefix, sizeof(ll_prefix));
1357 memcpy(&src.v6.s6_addr[sizeof(ll_prefix)], ip6h->ip6_src.s6_addr, 16-sizeof(ll_prefix));
1358 }
1359 } else {
1360 printf("Dropping packet with invalid IP version %u\n", iph->version);
1361 return 0;
1362 }
jjakoa7cd2492003-04-11 09:40:12 +00001363
Harald Weltebed35df2011-11-02 13:06:18 +01001364 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001365 printf("Dropping packet from invalid source address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001366 in46a_ntoa(&src));
Harald Weltebed35df2011-11-02 13:06:18 +01001367 return 0;
1368 }
1369
1370 if (ipm->pdp) /* Check if a peer protocol is defined */
1371 gtp_data_req(gsn, ipm->pdp, pack, len);
1372 return 0;
jjako52c24142002-12-16 13:33:51 +00001373}
1374
Harald Weltefed33892017-10-10 09:02:45 +08001375static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001376{
Harald Welted12eab92017-08-02 19:49:47 +02001377 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001378
Harald Weltebed35df2011-11-02 13:06:18 +01001379 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001380
Harald Weltebed35df2011-11-02 13:06:18 +01001381 if (cause < 0) {
1382 printf("Create PDP Context Request timed out\n");
1383 if (iph->pdp->version == 1) {
1384 printf("Retrying with version 0\n");
1385 iph->pdp->version = 0;
1386 gtp_create_context_req(gsn, iph->pdp, iph);
1387 return 0;
1388 } else {
1389 state = 0;
1390 pdp_freepdp(iph->pdp);
1391 iph->pdp = NULL;
1392 return EOF;
1393 }
1394 }
jjako2c381332003-10-21 19:09:53 +00001395
Harald Weltebed35df2011-11-02 13:06:18 +01001396 if (cause != 128) {
1397 printf
1398 ("Received create PDP context response. Cause value: %d\n",
1399 cause);
1400 state = 0;
1401 pdp_freepdp(iph->pdp);
1402 iph->pdp = NULL;
1403 return EOF; /* Not what we expected */
1404 }
jjako52c24142002-12-16 13:33:51 +00001405
Harald Weltea0d281d2017-08-02 21:48:16 +02001406 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001407 printf
1408 ("Received create PDP context response. Cause value: %d\n",
1409 cause);
1410 pdp_freepdp(iph->pdp);
1411 iph->pdp = NULL;
1412 state = 0;
1413 return EOF; /* Not a valid IP address */
1414 }
jjakoa7cd2492003-04-11 09:40:12 +00001415
Harald Weltebed35df2011-11-02 13:06:18 +01001416 printf("Received create PDP context response. IP address: %s\n",
Harald Welte6748dc92017-09-24 21:54:59 +08001417 in46a_ntoa(&addr));
1418
1419 switch (addr.len) {
1420 case 16: /* IPv6 */
1421 /* we have to enable the kernel to perform stateless autoconfiguration,
1422 * i.e. send a router solicitation using the lover 64bits of the allocated
1423 * EUA as interface identifier, as per 3GPP TS 29.061 Section 11.2.1.3.2 */
1424 memcpy(addr.v6.s6_addr, ll_prefix, sizeof(ll_prefix));
1425 printf("Derived IPv6 link-local address: %s\n", in46a_ntoa(&addr));
1426 break;
1427 case 4: /* IPv4 */
1428 break;
1429 }
jjakoa7cd2492003-04-11 09:40:12 +00001430
Harald Weltebed35df2011-11-02 13:06:18 +01001431 if ((options.createif) && (!options.net.s_addr)) {
Harald Welte6748dc92017-09-24 21:54:59 +08001432 size_t prefixlen = 32;
1433 if (addr.len == 16)
1434 prefixlen = 64;
Harald Weltebed35df2011-11-02 13:06:18 +01001435 /* printf("Setting up interface and routing\n"); */
Harald Welte6748dc92017-09-24 21:54:59 +08001436 /* FIXME: use tun_addattr() not tun_setaddr() */
1437 tun_setaddr(tun, &addr, &addr, prefixlen);
Harald Weltebed35df2011-11-02 13:06:18 +01001438 if (options.defaultroute) {
1439 struct in_addr rm;
1440 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001441 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001442 }
1443 if (options.ipup)
1444 tun_runscript(tun, options.ipup);
1445 }
jjako52c24142002-12-16 13:33:51 +00001446
Harald Welte081f30c2017-10-10 09:36:35 +08001447 /* now that ip-up has been executed, check if we are configured to
1448 * accept router advertisements */
1449 if (options.createif && options.pdp_type == PDP_EUA_TYPE_v6) {
1450 char *accept_ra, *forwarding;
1451
1452 accept_ra = proc_ipv6_conf_read(tun->devname, "accept_ra");
1453 forwarding = proc_ipv6_conf_read(tun->devname, "forwarding");
1454 if (!accept_ra || !forwarding)
1455 printf("Could not open proc file for %s ?!?\n", tun->devname);
1456 else {
1457 if (!strcmp(accept_ra, "0") ||
1458 (!strcmp(forwarding, "1") && !strcmp(accept_ra, "1"))) {
1459 printf("%s is %s, i.e. your tun device is not configured to accept "
1460 "router advertisements; SLAAC will not suceed, please "
1461 "fix your setup!\n");
1462 }
1463 free(accept_ra);
1464 free(forwarding);
1465 }
1466 }
1467
Harald Weltebed35df2011-11-02 13:06:18 +01001468 ipset((struct iphash_t *)pdp->peer, &addr);
1469
1470 state = 2; /* Connected */
1471
1472 return 0;
jjako52c24142002-12-16 13:33:51 +00001473}
1474
Harald Weltefed33892017-10-10 09:02:45 +08001475static int delete_pdp_conf(struct pdp_t *pdp, int cause)
Harald Weltebed35df2011-11-02 13:06:18 +01001476{
1477 printf("Received delete PDP context response. Cause value: %d\n",
1478 cause);
1479 return 0;
jjako52c24142002-12-16 13:33:51 +00001480}
1481
Harald Weltefed33892017-10-10 09:02:45 +08001482static int echo_conf(int recovery)
Harald Weltebed35df2011-11-02 13:06:18 +01001483{
jjako91aaf222003-10-22 10:09:32 +00001484
Harald Weltebed35df2011-11-02 13:06:18 +01001485 if (recovery < 0) {
1486 printf("Echo Request timed out\n");
1487 if (echoversion == 1) {
1488 printf("Retrying with version 0\n");
1489 echoversion = 0;
1490 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1491 return 0;
1492 } else {
1493 state = 0;
1494 return EOF;
1495 }
1496 } else {
1497 printf("Received echo response\n");
1498 if (!options.contexts)
1499 state = 5;
1500 }
1501 return 0;
jjako52c24142002-12-16 13:33:51 +00001502}
1503
Harald Weltefed33892017-10-10 09:02:45 +08001504static int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
Harald Weltebed35df2011-11-02 13:06:18 +01001505{
1506 /* if (cause < 0) return 0; Some error occurred. We don't care */
1507 switch (type) {
1508 case GTP_ECHO_REQ:
1509 return echo_conf(cause);
1510 case GTP_CREATE_PDP_REQ:
1511 return create_pdp_conf(pdp, cbp, cause);
1512 case GTP_DELETE_PDP_REQ:
1513 if (cause != 128)
1514 return 0; /* Request not accepted. We don't care */
1515 return delete_pdp_conf(pdp, cause);
1516 default:
1517 return 0;
1518 }
jjako52c24142002-12-16 13:33:51 +00001519}
1520
Harald Weltefed33892017-10-10 09:02:45 +08001521static int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
Harald Weltebed35df2011-11-02 13:06:18 +01001522{
1523 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1524 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001525}
1526
1527int main(int argc, char **argv)
1528{
Harald Weltebed35df2011-11-02 13:06:18 +01001529 fd_set fds; /* For select() */
1530 struct timeval idleTime; /* How long to select() */
1531 struct pdp_t *pdp;
1532 int n;
1533 int starttime = time(NULL); /* Time program was started */
1534 int stoptime = 0; /* Time to exit */
1535 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001536 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001537
Harald Weltebed35df2011-11-02 13:06:18 +01001538 struct timezone tz; /* Used for calculating ping times */
1539 struct timeval tv;
1540 int diff;
jjako52c24142002-12-16 13:33:51 +00001541
bjovana8f71eb2017-02-24 17:39:20 +01001542 signal(SIGTERM, signal_handler);
1543 signal(SIGHUP, signal_handler);
1544 signal(SIGINT, signal_handler);
1545
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001546 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001547
Harald Weltebed35df2011-11-02 13:06:18 +01001548 /* Process options given in configuration file and command line */
1549 if (process_options(argc, argv))
1550 exit(1);
jjako52c24142002-12-16 13:33:51 +00001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 printf("\nInitialising GTP library\n");
1553 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001554 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001555 exit(1);
1556 }
1557 if (gsn->fd0 > maxfd)
1558 maxfd = gsn->fd0;
1559 if (gsn->fd1c > maxfd)
1560 maxfd = gsn->fd1c;
1561 if (gsn->fd1u > maxfd)
1562 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001563
Harald Weltebed35df2011-11-02 13:06:18 +01001564 gtp_set_cb_delete_context(gsn, delete_context);
1565 gtp_set_cb_conf(gsn, conf);
1566 if (options.createif)
1567 gtp_set_cb_data_ind(gsn, encaps_tun);
1568 else
1569 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001570
Harald Weltebed35df2011-11-02 13:06:18 +01001571 if (options.createif) {
1572 printf("Setting up interface\n");
1573 /* Create a tunnel interface */
Harald Welte73abc382017-10-10 08:50:11 +08001574 if (tun_new((struct tun_t **)&tun, options.tun_dev_name)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001575 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001576 "Failed to create tun");
1577 exit(1);
1578 }
1579 tun_set_cb_ind(tun, cb_tun_ind);
1580 if (tun->fd > maxfd)
1581 maxfd = tun->fd;
1582 }
jjakoa7cd2492003-04-11 09:40:12 +00001583
Harald Weltebed35df2011-11-02 13:06:18 +01001584 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001585 struct in_addr mask;
1586 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001587 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001588 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001589 if (options.defaultroute) {
1590 struct in_addr rm;
1591 rm.s_addr = 0;
1592 tun_addroute(tun, &rm, &options.destaddr, &rm);
1593 }
1594 if (options.ipup)
1595 tun_runscript(tun, options.ipup);
1596 }
jjakoa7cd2492003-04-11 09:40:12 +00001597
Harald Weltebed35df2011-11-02 13:06:18 +01001598 /* Initialise hash tables */
1599 memset(&iphash, 0, sizeof(iphash));
1600 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001601
Harald Weltebed35df2011-11-02 13:06:18 +01001602 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001603
Harald Weltebed35df2011-11-02 13:06:18 +01001604 /* See if anybody is there */
1605 printf("Sending off echo request\n");
1606 echoversion = options.gtpversion;
1607 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001608
Harald Weltebed35df2011-11-02 13:06:18 +01001609 for (n = 0; n < options.contexts; n++) {
1610 uint64_t myimsi;
1611 printf("Setting up PDP context #%d\n", n);
1612 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001613
Harald Weltebed35df2011-11-02 13:06:18 +01001614 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001615
Harald Weltebed35df2011-11-02 13:06:18 +01001616 /* Allocated here. */
1617 /* If create context failes we have to deallocate ourselves. */
1618 /* Otherwise it is deallocated by gtplib */
1619 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001620
Harald Weltebed35df2011-11-02 13:06:18 +01001621 pdp->peer = &iparr[n];
1622 pdp->ipif = tun; /* TODO */
1623 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001624
Harald Weltebed35df2011-11-02 13:06:18 +01001625 if (options.gtpversion == 0) {
1626 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001627 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001628 "QoS length too big");
1629 exit(1);
1630 } else {
1631 memcpy(pdp->qos_req0, options.qos.v,
1632 options.qos.l);
1633 }
1634 }
jjakoa7cd2492003-04-11 09:40:12 +00001635
Harald Weltebed35df2011-11-02 13:06:18 +01001636 pdp->qos_req.l = options.qos.l;
1637 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001638
Harald Weltebed35df2011-11-02 13:06:18 +01001639 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001640
Harald Weltebed35df2011-11-02 13:06:18 +01001641 pdp->rattype.l = options.rattype.l;
1642 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1643 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001644
Harald Weltebed35df2011-11-02 13:06:18 +01001645 pdp->userloc.l = options.userloc.l;
1646 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1647 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001648
Harald Weltebed35df2011-11-02 13:06:18 +01001649 pdp->rai.l = options.rai.l;
1650 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1651 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001652
Harald Weltebed35df2011-11-02 13:06:18 +01001653 pdp->mstz.l = options.mstz.l;
1654 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1655 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001656
Harald Weltebed35df2011-11-02 13:06:18 +01001657 pdp->imeisv.l = options.imeisv.l;
1658 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1659 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001660
Harald Weltebed35df2011-11-02 13:06:18 +01001661 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001662
Harald Weltebed35df2011-11-02 13:06:18 +01001663 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001664 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001665 "APN length too big");
1666 exit(1);
1667 } else {
1668 pdp->apn_use.l = options.apn.l;
1669 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1670 }
jjako193e8b12003-11-10 12:31:41 +00001671
Harald Weltebed35df2011-11-02 13:06:18 +01001672 pdp->gsnlc.l = sizeof(options.listen);
1673 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1674 pdp->gsnlu.l = sizeof(options.listen);
1675 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001676
Harald Weltebed35df2011-11-02 13:06:18 +01001677 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001678 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001679 "MSISDN length too big");
1680 exit(1);
1681 } else {
1682 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1683 }
jjakob62c3dd2004-05-27 18:51:55 +00001684
Harald Welte840a8e92017-09-24 18:12:40 +08001685 /* Request dynamic IP address */
1686 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1687 pdp->eua.v[1] = options.pdp_type;
1688 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001689
Harald Weltebed35df2011-11-02 13:06:18 +01001690 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001691 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001692 "PCO length too big");
1693 exit(1);
1694 } else {
1695 pdp->pco_req.l = options.pco.l;
1696 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1697 }
jjako52c24142002-12-16 13:33:51 +00001698
Harald Weltebed35df2011-11-02 13:06:18 +01001699 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001700
Harald Weltebed35df2011-11-02 13:06:18 +01001701 pdp->hisaddr0 = options.remote;
1702 pdp->hisaddr1 = options.remote;
1703
1704 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1705 512 = Flat rate, 256 = Hot billing */
1706
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001707 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1708
Harald Weltebed35df2011-11-02 13:06:18 +01001709 /* Create context */
1710 /* We send this of once. Retransmissions are handled by gtplib */
1711 gtp_create_context_req(gsn, pdp, &iparr[n]);
1712 }
1713
1714 state = 1; /* Enter wait_connection state */
1715
1716 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001717
jjako52c24142002-12-16 13:33:51 +00001718 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001719 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001720 /******************************************************************/
1721
Harald Weltebed35df2011-11-02 13:06:18 +01001722 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001723
Harald Weltebed35df2011-11-02 13:06:18 +01001724 /* Take down client after timeout after disconnect */
1725 if ((4 == state) && ((stoptime) <= time(NULL))) {
1726 state = 5;
1727 }
jjako7b8fad42003-07-07 14:37:42 +00001728
Harald Weltebed35df2011-11-02 13:06:18 +01001729 /* Take down client after timelimit timeout */
1730 if ((2 == state) && (options.timelimit) &&
1731 ((starttime + options.timelimit) <= time(NULL))) {
1732 state = 3;
1733 }
jjako7b8fad42003-07-07 14:37:42 +00001734
Harald Weltebed35df2011-11-02 13:06:18 +01001735 /* Take down client after ping timeout */
1736 if ((2 == state) && (pingtimeout)
1737 && (pingtimeout <= time(NULL))) {
1738 state = 3;
1739 }
jjako7b8fad42003-07-07 14:37:42 +00001740
Harald Weltebed35df2011-11-02 13:06:18 +01001741 /* Set pingtimeout for later disconnection */
1742 if (options.pingcount && ntransmitted >= options.pingcount) {
1743 pingtimeout = time(NULL) + 5; /* Extra seconds */
1744 }
jjako7b8fad42003-07-07 14:37:42 +00001745
Harald Weltebed35df2011-11-02 13:06:18 +01001746 /* Print statistics if no more ping packets are missing */
1747 if (ntransmitted && options.pingcount
1748 && nreceived >= options.pingcount) {
1749 ping_finish();
1750 if (!options.createif)
1751 state = 3;
1752 }
jjako7b8fad42003-07-07 14:37:42 +00001753
Harald Weltebed35df2011-11-02 13:06:18 +01001754 /* Send off disconnect */
1755 if (3 == state) {
1756 state = 4;
1757 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1758 for (n = 0; n < options.contexts; n++) {
1759 /* Delete context */
1760 printf("Disconnecting PDP context #%d\n", n);
1761 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1762 1);
1763 if ((options.pinghost.s_addr != 0)
1764 && ntransmitted)
1765 ping_finish();
1766 }
1767 }
jjako7b8fad42003-07-07 14:37:42 +00001768
Harald Weltebed35df2011-11-02 13:06:18 +01001769 /* Send of ping packets */
1770 diff = 0;
1771 while ((diff <= 0) &&
1772 /* Send off an ICMP ping packet */
1773 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1774 ((pingseq < options.pingcount)
1775 || (options.pingcount == 0))) {
1776 if (!pingseq)
1777 gettimeofday(&firstping, &tz); /* Set time of first ping */
1778 gettimeofday(&tv, &tz);
1779 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1780 if (diff <= 0) {
1781 if (options.debug)
1782 printf("Create_ping %d\n", diff);
1783 create_ping(gsn,
1784 iparr[pingseq %
1785 options.contexts].pdp,
1786 &options.pinghost, pingseq,
1787 options.pingsize);
1788 pingseq++;
1789 }
1790 }
jjako5da68452003-01-28 16:08:47 +00001791
Harald Weltebed35df2011-11-02 13:06:18 +01001792 FD_ZERO(&fds);
1793 if (tun)
1794 FD_SET(tun->fd, &fds);
1795 FD_SET(gsn->fd0, &fds);
1796 FD_SET(gsn->fd1c, &fds);
1797 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001798
Harald Weltebed35df2011-11-02 13:06:18 +01001799 gtp_retranstimeout(gsn, &idleTime);
1800 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001801
Harald Weltebed35df2011-11-02 13:06:18 +01001802 if (options.debug)
1803 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1804 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001805
bjovana8f71eb2017-02-24 17:39:20 +01001806 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001807 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1808 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001809 if (errno == EINTR)
1810 signal_received = 1;
1811 else
1812 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1813 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001814 break;
1815 case 0:
1816 gtp_retrans(gsn); /* Only retransmit if nothing else */
1817 break;
1818 default:
1819 break;
1820 }
1821
bjovana8f71eb2017-02-24 17:39:20 +01001822 if (!signal_received) {
1823
1824 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1825 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1826 "TUN decaps failed");
1827 }
1828
1829 if (FD_ISSET(gsn->fd0, &fds))
1830 gtp_decaps0(gsn);
1831
1832 if (FD_ISSET(gsn->fd1c, &fds))
1833 gtp_decaps1c(gsn);
1834
1835 if (FD_ISSET(gsn->fd1u, &fds))
1836 gtp_decaps1u(gsn);
1837
Harald Weltebed35df2011-11-02 13:06:18 +01001838 }
Harald Weltebed35df2011-11-02 13:06:18 +01001839 }
1840
1841 gtp_free(gsn); /* Clean up the gsn instance */
1842
1843 if (options.createif)
1844 tun_free(tun);
1845
1846 if (0 == state)
1847 exit(1); /* Indicate error */
1848
1849 return 0;
jjako52c24142002-12-16 13:33:51 +00001850}