blob: 1567e7e3e82e88b1809e958114a439f40e719abd [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
jjako52c24142002-12-16 13:33:51 +00004 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/*
13 * sgsnemu.c
14 *
15 */
16
jjako52c24142002-12-16 13:33:51 +000017#ifdef __linux__
Harald Weltebed35df2011-11-02 13:06:18 +010018#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000019#endif
20
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010021#include <osmocom/core/application.h>
22
jjako52c24142002-12-16 13:33:51 +000023#include <ctype.h>
24#include <netdb.h>
25#include <signal.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <netinet/in.h>
32#include <arpa/inet.h>
33#include <sys/wait.h>
34#include <sys/stat.h>
35#include <unistd.h>
36#include <sys/socket.h>
37#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000038#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000039#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000040#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000041#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000042#include <resolv.h>
43#include <time.h>
44
jjakoff9985c2004-01-16 11:05:22 +000045#include "config.h"
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020046#include "../lib/tun.h"
47#include "../lib/ippool.h"
48#include "../lib/syserr.h"
jjako52c24142002-12-16 13:33:51 +000049#include "../gtp/pdp.h"
50#include "../gtp/gtp.h"
51#include "cmdline.h"
52
Harald Weltebed35df2011-11-02 13:06:18 +010053#define IPADDRLEN 256 /* Character length of addresses */
54#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000055
jjakoa7cd2492003-04-11 09:40:12 +000056/* HASH tables for IP address allocation */
57struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010058 uint8_t inuse; /* 0=free. 1=used by somebody */
59 struct iphash_t *ipnext;
60 struct pdp_t *pdp;
61 struct in_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000062};
63struct iphash_t iparr[MAXCONTEXTS];
64struct iphash_t *iphash[MAXCONTEXTS];
65
66/* State variable used for ping */
67/* 0: Idle */
68/* 1: Wait_connect */
69/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000070/* 3: Done */
71/* 4: Wait_disconnect */
72/* 5: Disconnected */
bjovana8f71eb2017-02-24 17:39:20 +010073volatile sig_atomic_t state = 0;
jjako52c24142002-12-16 13:33:51 +000074
Harald Weltebed35df2011-11-02 13:06:18 +010075struct gsn_t *gsn = NULL; /* GSN instance */
76struct tun_t *tun = NULL; /* TUN instance */
77int maxfd = 0; /* For select() */
78int echoversion = 1; /* First try this version */
jjako52c24142002-12-16 13:33:51 +000079
jjakoa7cd2492003-04-11 09:40:12 +000080/* Struct with local versions of gengetopt options */
81struct {
Harald Weltebed35df2011-11-02 13:06:18 +010082 int debug; /* Print debug messages */
83 int createif; /* Create local network interface */
84 struct in_addr netaddr, destaddr, net, mask; /* Network interface */
85 char *ipup, *ipdown; /* Filename of scripts */
86 int defaultroute; /* Set up default route */
87 struct in_addr pinghost; /* Remote ping host */
88 int pingrate;
89 int pingsize;
90 int pingcount;
91 int pingquiet;
92 struct in_addr listen;
93 struct in_addr remote;
94 struct in_addr dns;
95 int contexts; /* Number of contexts to create */
96 int timelimit; /* Number of seconds to be connected */
97 char *statedir;
98 uint64_t imsi;
99 uint8_t nsapi;
100 int gtpversion;
101 struct ul255_t pco;
102 struct ul255_t qos;
103 uint16_t cch;
104 struct ul255_t apn;
105 uint8_t selmode;
106 struct ul255_t rattype;
107 int rattype_given;
108 struct ul255_t userloc;
109 int userloc_given;
110 struct ul255_t rai;
111 int rai_given;
112 struct ul255_t mstz;
113 int mstz_given;
114 struct ul255_t imeisv;
115 int imeisv_given;
116 struct ul16_t msisdn;
117 int norecovery_given;
jjakoa7cd2492003-04-11 09:40:12 +0000118} options;
jjako52c24142002-12-16 13:33:51 +0000119
jjako5da68452003-01-28 16:08:47 +0000120/* Definitions to use for PING. Most of the ping code was derived from */
121/* the original ping program by Mike Muuss */
122
123/* IP header and ICMP echo header */
124#define CREATEPING_MAX 2048
125#define CREATEPING_IP 20
126#define CREATEPING_ICMP 8
127
128struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100129 uint8_t ipver; /* Type and header length */
130 uint8_t tos; /* Type of Service */
131 uint16_t length; /* Total length */
132 uint16_t fragid; /* Identifier */
133 uint16_t offset; /* Flags and fragment offset */
134 uint8_t ttl; /* Time to live */
135 uint8_t protocol; /* Protocol */
136 uint16_t ipcheck; /* Header checksum */
137 uint32_t src; /* Source address */
138 uint32_t dst; /* Destination */
139 uint8_t type; /* Type and header length */
140 uint8_t code; /* Code */
141 uint16_t checksum; /* Header checksum */
142 uint16_t ident; /* Identifier */
143 uint16_t seq; /* Sequence number */
144 uint8_t data[CREATEPING_MAX]; /* Data */
145} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000146
147/* Statistical values for ping */
148int nreceived = 0;
149int ntreceived = 0;
150int ntransmitted = 0;
151int tmin = 999999999;
152int tmax = 0;
153int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100154int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000155struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000156
bjovana8f71eb2017-02-24 17:39:20 +0100157void signal_handler(int signo)
158{
159 if (state == 2)
160 state = 3; /* Tell main loop to finish. */
161}
162
Harald Weltebed35df2011-11-02 13:06:18 +0100163int ipset(struct iphash_t *ipaddr, struct in_addr *addr)
164{
165 int hash = ippool_hash4(addr) % MAXCONTEXTS;
166 struct iphash_t *h;
167 struct iphash_t *prev = NULL;
168 ipaddr->ipnext = NULL;
169 ipaddr->addr.s_addr = addr->s_addr;
170 for (h = iphash[hash]; h; h = h->ipnext)
171 prev = h;
172 if (!prev)
173 iphash[hash] = ipaddr;
174 else
175 prev->ipnext = ipaddr;
176 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000177}
178
Harald Weltebed35df2011-11-02 13:06:18 +0100179int ipdel(struct iphash_t *ipaddr)
180{
181 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
182 struct iphash_t *h;
183 struct iphash_t *prev = NULL;
184 for (h = iphash[hash]; h; h = h->ipnext) {
185 if (h == ipaddr) {
186 if (!prev)
187 iphash[hash] = h->ipnext;
188 else
189 prev->ipnext = h->ipnext;
190 return 0;
191 }
192 prev = h;
193 }
194 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000195}
196
Harald Weltebed35df2011-11-02 13:06:18 +0100197int ipget(struct iphash_t **ipaddr, struct in_addr *addr)
198{
199 int hash = ippool_hash4(addr) % MAXCONTEXTS;
200 struct iphash_t *h;
201 for (h = iphash[hash]; h; h = h->ipnext) {
202 if ((h->addr.s_addr == addr->s_addr)) {
203 *ipaddr = h;
204 return 0;
205 }
206 }
207 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000208}
209
jjakoa7cd2492003-04-11 09:40:12 +0000210/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +0100211void log_pid(char *pidfile)
212{
213 FILE *file;
214 mode_t oldmask;
215
216 oldmask = umask(022);
217 file = fopen(pidfile, "w");
218 umask(oldmask);
219 if (!file)
220 return;
221 fprintf(file, "%d\n", (int)getpid());
222 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000223}
224
Harald Weltebed35df2011-11-02 13:06:18 +0100225int process_options(int argc, char **argv)
226{
227 /* gengeopt declarations */
228 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000229
Harald Weltebed35df2011-11-02 13:06:18 +0100230 struct hostent *host;
231 unsigned int n;
232 uint16_t i;
233 uint8_t a;
234 uint8_t b;
235 char *tmp;
236 char *pch;
237 char *type;
238 char *mcc;
239 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100240 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100241 char *lac;
242 int lac_d;
243 char *rest;
244 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
245 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
246 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
247 int sign;
248 int nbquarters;
249 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000250
Harald Weltebed35df2011-11-02 13:06:18 +0100251 if (cmdline_parser(argc, argv, &args_info) != 0)
252 return -1;
253 if (args_info.debug_flag) {
254 if (args_info.remote_arg)
255 printf("remote: %s\n", args_info.remote_arg);
256 if (args_info.listen_arg)
257 printf("listen: %s\n", args_info.listen_arg);
258 if (args_info.conf_arg)
259 printf("conf: %s\n", args_info.conf_arg);
260 printf("debug: %d\n", args_info.debug_flag);
261 if (args_info.imsi_arg)
262 printf("imsi: %s\n", args_info.imsi_arg);
263 printf("qos: %#08x\n", args_info.qos_arg);
264 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
265 printf("qose2: %#04x\n", args_info.qose2_arg);
266 printf("qose3: %#06x\n", args_info.qose3_arg);
267 printf("qose4: %#06x\n", args_info.qose4_arg);
268 printf("charging: %#04x\n", args_info.charging_arg);
269 if (args_info.apn_arg)
270 printf("apn: %s\n", args_info.apn_arg);
271 if (args_info.msisdn_arg)
272 printf("msisdn: %s\n", args_info.msisdn_arg);
273 if (args_info.uid_arg)
274 printf("uid: %s\n", args_info.uid_arg);
275 if (args_info.pwd_arg)
276 printf("pwd: %s\n", args_info.pwd_arg);
277 if (args_info.pidfile_arg)
278 printf("pidfile: %s\n", args_info.pidfile_arg);
279 if (args_info.statedir_arg)
280 printf("statedir: %s\n", args_info.statedir_arg);
281 if (args_info.dns_arg)
282 printf("dns: %s\n", args_info.dns_arg);
283 printf("contexts: %d\n", args_info.contexts_arg);
284 printf("timelimit: %d\n", args_info.timelimit_arg);
285 printf("createif: %d\n", args_info.createif_flag);
286 if (args_info.ipup_arg)
287 printf("ipup: %s\n", args_info.ipup_arg);
288 if (args_info.ipdown_arg)
289 printf("ipdown: %s\n", args_info.ipdown_arg);
290 printf("defaultroute: %d\n", args_info.defaultroute_flag);
291 if (args_info.pinghost_arg)
292 printf("pinghost: %s\n", args_info.pinghost_arg);
293 printf("pingrate: %d\n", args_info.pingrate_arg);
294 printf("pingsize: %d\n", args_info.pingsize_arg);
295 printf("pingcount: %d\n", args_info.pingcount_arg);
296 printf("pingquiet: %d\n", args_info.pingquiet_flag);
297 printf("norecovery: %d\n", args_info.norecovery_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100298 }
jjakoa7cd2492003-04-11 09:40:12 +0000299
Harald Weltebed35df2011-11-02 13:06:18 +0100300 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000301
Harald Weltebed35df2011-11-02 13:06:18 +0100302 if (args_info.conf_arg) {
303 if (cmdline_parser_configfile
304 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
305 return -1;
306 if (args_info.debug_flag) {
307 printf("cmdline_parser_configfile\n");
308 if (args_info.remote_arg)
309 printf("remote: %s\n", args_info.remote_arg);
310 if (args_info.listen_arg)
311 printf("listen: %s\n", args_info.listen_arg);
312 if (args_info.conf_arg)
313 printf("conf: %s\n", args_info.conf_arg);
314 printf("debug: %d\n", args_info.debug_flag);
315 if (args_info.imsi_arg)
316 printf("imsi: %s\n", args_info.imsi_arg);
317 printf("qos: %#08x\n", args_info.qos_arg);
318 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
319 printf("qose2: %#04x\n", args_info.qose2_arg);
320 printf("qose3: %#06x\n", args_info.qose3_arg);
321 printf("qose4: %#06x\n", args_info.qose4_arg);
322 printf("charging: %#04x\n", args_info.charging_arg);
323 if (args_info.apn_arg)
324 printf("apn: %s\n", args_info.apn_arg);
325 if (args_info.msisdn_arg)
326 printf("msisdn: %s\n", args_info.msisdn_arg);
327 if (args_info.uid_arg)
328 printf("uid: %s\n", args_info.uid_arg);
329 if (args_info.pwd_arg)
330 printf("pwd: %s\n", args_info.pwd_arg);
331 if (args_info.pidfile_arg)
332 printf("pidfile: %s\n", args_info.pidfile_arg);
333 if (args_info.statedir_arg)
334 printf("statedir: %s\n",
335 args_info.statedir_arg);
336 if (args_info.dns_arg)
337 printf("dns: %s\n", args_info.dns_arg);
338 printf("contexts: %d\n", args_info.contexts_arg);
339 printf("timelimit: %d\n", args_info.timelimit_arg);
340 printf("createif: %d\n", args_info.createif_flag);
341 if (args_info.ipup_arg)
342 printf("ipup: %s\n", args_info.ipup_arg);
343 if (args_info.ipdown_arg)
344 printf("ipdown: %s\n", args_info.ipdown_arg);
345 printf("defaultroute: %d\n",
346 args_info.defaultroute_flag);
347 if (args_info.pinghost_arg)
348 printf("pinghost: %s\n",
349 args_info.pinghost_arg);
350 printf("pingrate: %d\n", args_info.pingrate_arg);
351 printf("pingsize: %d\n", args_info.pingsize_arg);
352 printf("pingcount: %d\n", args_info.pingcount_arg);
353 printf("pingquiet: %d\n", args_info.pingquiet_flag);
354 printf("norecovery: %d\n", args_info.norecovery_flag);
355 }
356 }
jjako193e8b12003-11-10 12:31:41 +0000357
Harald Weltebed35df2011-11-02 13:06:18 +0100358 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000359
Harald Weltebed35df2011-11-02 13:06:18 +0100360 /* foreground */
361 /* If fg flag not given run as a daemon */
362 /* Do not allow sgsnemu to run as deamon
363 if (!args_info.fg_flag)
364 {
365 closelog();
366 freopen("/dev/null", "w", stdout);
367 freopen("/dev/null", "w", stderr);
368 freopen("/dev/null", "r", stdin);
369 daemon(0, 0);
370 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
371 } */
jjako1a51df72004-07-20 08:30:21 +0000372
Harald Weltebed35df2011-11-02 13:06:18 +0100373 /* debug */
374 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000375
Harald Weltebed35df2011-11-02 13:06:18 +0100376 /* pidfile */
377 /* This has to be done after we have our final pid */
378 if (args_info.pidfile_arg) {
379 log_pid(args_info.pidfile_arg);
380 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200381
Harald Weltebed35df2011-11-02 13:06:18 +0100382 /* dns */
383 /* If no dns option is given use system default */
384 /* Do hostname lookup to translate hostname to IP address */
385 printf("\n");
386 if (args_info.dns_arg) {
387 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100388 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100389 "Invalid DNS address: %s!", args_info.dns_arg);
390 return -1;
391 } else {
392 memcpy(&options.dns.s_addr, host->h_addr,
393 host->h_length);
394 _res.nscount = 1;
395 _res.nsaddr_list[0].sin_addr = options.dns;
396 printf("Using DNS server: %s (%s)\n",
397 args_info.dns_arg, inet_ntoa(options.dns));
398 }
399 } else {
400 options.dns.s_addr = 0;
401 printf("Using default DNS server\n");
402 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200403
Harald Weltebed35df2011-11-02 13:06:18 +0100404 /* listen */
405 /* If no listen option is specified listen to any local port */
406 /* Do hostname lookup to translate hostname to IP address */
407 if (args_info.listen_arg) {
408 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100409 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100410 "Invalid listening address: %s!",
411 args_info.listen_arg);
412 return -1;
413 } else {
414 memcpy(&options.listen.s_addr, host->h_addr,
415 host->h_length);
416 printf("Local IP address is: %s (%s)\n",
417 args_info.listen_arg, inet_ntoa(options.listen));
418 }
419 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100420 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100421 "Listening address must be specified: %s!",
422 args_info.listen_arg);
423 return -1;
424 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200425
Harald Weltebed35df2011-11-02 13:06:18 +0100426 /* remote */
427 /* If no remote option is specified terminate */
428 /* Do hostname lookup to translate hostname to IP address */
429 if (args_info.remote_arg) {
430 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100431 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100432 "Invalid remote address: %s!",
433 args_info.remote_arg);
434 return -1;
435 } else {
436 memcpy(&options.remote.s_addr, host->h_addr,
437 host->h_length);
438 printf("Remote IP address is: %s (%s)\n",
439 args_info.remote_arg, inet_ntoa(options.remote));
440 }
441 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100442 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100443 "No remote address given!");
444 return -1;
445 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200446
Harald Weltebed35df2011-11-02 13:06:18 +0100447 /* imsi */
448 if (strlen(args_info.imsi_arg) != 15) {
449 printf("Invalid IMSI\n");
450 return -1;
451 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200452
Harald Weltebed35df2011-11-02 13:06:18 +0100453 options.imsi = 0xf000000000000000ull;
454 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
455 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
456 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
457 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
458 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
459 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
460 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
461 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
462 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
463 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
464 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
465 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
466 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
467 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
468 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200469
Harald Weltebed35df2011-11-02 13:06:18 +0100470 printf("IMSI is: %s (%#08llx)\n",
471 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200472
Harald Weltebed35df2011-11-02 13:06:18 +0100473 /* nsapi */
474 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
475 printf("Invalid NSAPI\n");
476 return -1;
477 }
478 options.nsapi = args_info.nsapi_arg;
479 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200480
Harald Weltebed35df2011-11-02 13:06:18 +0100481 /* qos */
482 options.qos.l = 4;
483 options.qos.v[3] = (args_info.qos_arg) & 0xff;
484 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
485 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
486 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
487 /* Extensions according to 3GPP TS 24.008 */
488 if (args_info.qose1_given == 1) {
489 options.qos.l = 12;
490 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
491 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
492 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
493 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
494 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
495 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
496 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
497 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
498 if (args_info.qose2_given == 1) {
499 options.qos.l = 13;
500 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
501 if (args_info.qose3_given == 1) {
502 options.qos.l = 15;
503 options.qos.v[14] =
504 (args_info.qose3_arg) & 0xff;
505 options.qos.v[13] =
506 ((args_info.qose3_arg) >> 8) & 0xff;
507 if (args_info.qose4_given == 1) {
508 options.qos.l = 17;
509 options.qos.v[16] =
510 (args_info.qose4_arg) & 0xff;
511 options.qos.v[15] =
512 ((args_info.qose4_arg) >> 8) & 0xff;
513 }
514 }
515 }
516 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200517
Harald Weltebed35df2011-11-02 13:06:18 +0100518 /* charging */
519 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200520
Harald Weltebed35df2011-11-02 13:06:18 +0100521 /* contexts */
522 if (args_info.contexts_arg > MAXCONTEXTS) {
523 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
524 return -1;
525 }
526 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200527
Harald Weltebed35df2011-11-02 13:06:18 +0100528 /* Timelimit */
529 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200530
Harald Weltebed35df2011-11-02 13:06:18 +0100531 /* gtpversion */
532 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
533 printf("Invalid GTP version\n");
534 return -1;
535 }
536 options.gtpversion = args_info.gtpversion_arg;
537 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200538
Harald Weltebed35df2011-11-02 13:06:18 +0100539 /* apn */
540 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
541 printf("Invalid APN\n");
542 return -1;
543 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100544 options.apn.l = strlen(args_info.apn_arg) + 1;
545
546 apn = (char *)options.apn.v;
547 for (tok = strtok(args_info.apn_arg, ".");
548 tok != NULL;
549 tok = strtok(NULL, ".")) {
550 size_t len = strlen(tok);
551
552 *apn++ = (char)len;
553 strncpy(apn, tok, len);
554 apn += len;
555 }
556
Harald Weltebed35df2011-11-02 13:06:18 +0100557 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200558
Harald Weltebed35df2011-11-02 13:06:18 +0100559 /* selmode */
560 options.selmode = args_info.selmode_arg;
561 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200562
Harald Weltebed35df2011-11-02 13:06:18 +0100563 /* rattype */
564 if (args_info.rattype_given == 1) {
565 options.rattype_given = 1;
566 options.rattype.l = strlen(args_info.rattype_arg);
567 options.rattype.v[0] = atoi(args_info.rattype_arg);
568 printf("Using RAT Type: %s\n", args_info.rattype_arg);
569 }
Harald Welte41af5692011-10-07 18:42:34 +0200570
Harald Weltebed35df2011-11-02 13:06:18 +0100571 /* userloc */
572 if (args_info.userloc_given == 1) {
573 printf("Using User Location Information: %s\n",
574 args_info.userloc_arg);
575 tmp = args_info.userloc_arg;
576 n = 0;
577 pch = strtok(tmp, ".");
578 while (pch != NULL) {
579 userloc_el[n] = pch;
580 pch = strtok(NULL, ".");
581 n++;
582 }
Harald Welte41af5692011-10-07 18:42:34 +0200583
Harald Weltebed35df2011-11-02 13:06:18 +0100584 options.userloc_given = 1;
585 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200586
Harald Weltebed35df2011-11-02 13:06:18 +0100587 /* 3GPP Geographic Location Type t0 / t1 / t2 */
588 type = userloc_el[0];
589 printf("->type : %c\n", type[0]);
590 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
591 printf("Invalid type \n");
592 return -1;
593 }
594 /* options.userloc.v[0] = 0x00 */
595 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200596
Harald Weltebed35df2011-11-02 13:06:18 +0100597 /* MCC */
598 mcc = userloc_el[1];
599 printf("->mcc : %s\n", mcc);
600 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200601 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100602 return -1;
603 }
Harald Welte41af5692011-10-07 18:42:34 +0200604
Harald Weltebed35df2011-11-02 13:06:18 +0100605 /* MNC */
606 mnc = userloc_el[2];
607 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200608
Harald Weltebed35df2011-11-02 13:06:18 +0100609 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
610 /* options.userloc.v[1] = 0x52 */
611 a = (uint8_t) (mcc[0] - 48);
612 b = (uint8_t) (mcc[1] - 48);
613 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200614
Harald Weltebed35df2011-11-02 13:06:18 +0100615 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
616 /* options.userloc.v[2] = 0xf0 */
617 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200618
Harald Weltebed35df2011-11-02 13:06:18 +0100619 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200620 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100621 return -1;
622 }
623 if (strlen(mnc) == 2) {
624 b = 15;
625 }
626 if (strlen(mnc) == 3) {
627 b = (uint8_t) (mnc[2] - 48);
628 }
629 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200630
Harald Weltebed35df2011-11-02 13:06:18 +0100631 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
632 /* options.userloc.v[3] = 0x99 */
633 a = (uint8_t) (mnc[0] - 48);
634 b = (uint8_t) (mnc[1] - 48);
635 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200636
Harald Weltebed35df2011-11-02 13:06:18 +0100637 /* LAC */
638 lac = userloc_el[3];
639 /*options.userloc.v[4] = 0x12 ; */
640 /*options.userloc.v[5] = 0x10 ; */
641 printf("->LAC: %s\n", lac);
642 lac_d = atoi(lac);
643 if (lac_d > 65535 || lac_d < 1) {
644 printf("Invalid LAC\n");
645 return -1;
646 }
647 i = lac_d >> 8;
648 options.userloc.v[4] = i; /* octet 8 - LAC */
649 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200650
Harald Weltebed35df2011-11-02 13:06:18 +0100651 /* CI/SAC/RAC */
652 rest = userloc_el[4];
653 printf("->CI/SAC/RAC : %s\n", rest);
654 lac_d = atoi(rest);
655 if (lac_d > 65535 || lac_d < 1) {
656 printf("Invalid CI/SAC/RAC\n");
657 return -1;
658 }
659 /*options.userloc.v[6] = 0x04 ; */
660 /*options.userloc.v[7] = 0xb7 ; */
661 i = lac_d >> 8;
662 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
663 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
664 }
jjakoa7cd2492003-04-11 09:40:12 +0000665
Harald Weltebed35df2011-11-02 13:06:18 +0100666 /* RAI */
667 if (args_info.rai_given == 1) {
668 printf("Using RAI: %s\n", args_info.rai_arg);
669 tmp = args_info.rai_arg;
670 n = 0;
671 pch = strtok(tmp, ".");
672 while (pch != NULL) {
673 rai_el[n] = pch;
674 pch = strtok(NULL, ".");
675 n++;
676 }
jjakoa7cd2492003-04-11 09:40:12 +0000677
Harald Weltebed35df2011-11-02 13:06:18 +0100678 options.rai_given = 1;
679 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000680
Harald Weltebed35df2011-11-02 13:06:18 +0100681 /* MCC */
682 mcc = rai_el[0];
683 printf("->mcc : %s\n", mcc);
684 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200685 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100686 return -1;
687 }
688
689 /* MNC */
690 mnc = rai_el[1];
691 printf("->mnc : %s\n", mnc);
692
693 a = (uint8_t) (mcc[0] - 48);
694 b = (uint8_t) (mcc[1] - 48);
695 options.rai.v[0] = 16 * b + a;
696
697 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
698 a = (uint8_t) (mcc[2] - 48);
699
700 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200701 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100702 return -1;
703 }
704 if (strlen(mnc) == 2) {
705 b = 15;
706 }
707 if (strlen(mnc) == 3) {
708 b = (uint8_t) (mnc[2] - 48);
709 }
710 options.rai.v[1] = 16 * b + a;
711
712 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
713 a = (uint8_t) (mnc[0] - 48);
714 b = (uint8_t) (mnc[1] - 48);
715 options.rai.v[2] = 16 * b + a;
716
717 /* LAC */
718 lac = rai_el[2];
719 printf("->LAC: %s\n", lac);
720 lac_d = atoi(lac);
721 if (lac_d > 65535 || lac_d < 1) {
722 printf("Invalid LAC\n");
723 return -1;
724 }
725 i = lac_d >> 8;
726 options.rai.v[3] = i; /* octet 5 - LAC */
727 options.rai.v[4] = lac_d; /* octet 6 - LAC */
728
729 /* RAC */
730 rest = rai_el[3];
731 printf("->RAC : %s\n", rest);
732 lac_d = atoi(rest);
733 if (lac_d > 255 || lac_d < 1) {
734 printf("Invalid RAC\n");
735 return -1;
736 }
737 options.rai.v[5] = lac_d; /* octet 7 - RAC */
738 }
739
740 /* mstz */
741 if (args_info.mstz_given == 1) {
742 options.mstz_given = 1;
743 options.mstz.l = 2;
744
745 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
746 tmp = args_info.mstz_arg;
747 n = 0;
748 pch = strtok(tmp, ".");
749 while (pch != NULL) {
750 mstz_el[n] = pch;
751 pch = strtok(NULL, ".");
752 n++;
753 }
754
755 /* sign */
756 sign = atoi(mstz_el[0]);
757 printf("->Sign (0=+ / 1=-): %d\n", sign);
758 if (sign != 0 && sign != 1) {
759 printf("Invalid Sign \n");
760 return -1;
761 }
762 /* nbquarters */
763 nbquarters = atoi(mstz_el[1]);
764 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
765 if (nbquarters < 0 || nbquarters > 79) {
766 printf("Invalid Number of Quarters \n");
767 return -1;
768 }
769 /* DST */
770 DST = atoi(mstz_el[2]);
771 printf("->Daylight Saving Time Adjustment : %d\n", DST);
772 if (DST < 0 || DST > 3) {
773 printf("Invalid DST Adjustment \n");
774 return -1;
775 }
776 /* 12345678
777 bits 123 = unit of # of quarters of an hour
778 bits 678 = # of quarters of an hour / 10
779 bit 5 = sign
780 */
781 i = nbquarters % 10;
782 i = i << 4;
783 i = i + nbquarters / 10 + 8 * sign;
784 /* options.mstz.v[0] = 0x69 ; */
785 /* options.mstz.v[1] = 0x01 ; */
786 options.mstz.v[0] = i;
787 options.mstz.v[1] = DST;
788 n = (i & 0x08) ? '-' : '+';
789 printf
790 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
791 n, nbquarters / 4, nbquarters % 4 * 15);
792 }
793
794 /* imeisv */
795 if (args_info.imeisv_given == 1) {
796 options.imeisv_given = 1;
797 if (strlen(args_info.imeisv_arg) != 16) {
798 printf("Invalid IMEI(SV)\n");
799 return -1;
800 }
801 options.imeisv.l = 8;
802 for (n = 0; n < 8; n++) {
803 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
804 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
805 options.imeisv.v[n] = 16 * b + a;
806 }
807 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
808 }
809
810 /* msisdn */
811 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
812 printf("Invalid MSISDN\n");
813 return -1;
814 }
815 options.msisdn.l = 1;
816 options.msisdn.v[0] = 0x91; /* International format */
817 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
818 if ((n % 2) == 0) {
819 options.msisdn.v[((int)n / 2) + 1] =
820 args_info.msisdn_arg[n] - 48 + 0xf0;
821 options.msisdn.l += 1;
822 } else {
823 options.msisdn.v[((int)n / 2) + 1] =
824 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
825 (args_info.msisdn_arg[n] - 48) * 16;
826 }
827 }
828 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
829
830 /* UID and PWD */
831 /* Might need to also insert stuff like DNS etc. */
832 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
833 (sizeof(options.pco.v) - 1)) {
834 printf("invalid UID and PWD\n");
835 return -1;
836 }
837 options.pco.l =
838 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
839 options.pco.v[0] = 0x80; /* PPP */
840 options.pco.v[1] = 0xc0; /* PAP */
841 options.pco.v[2] = 0x23;
842 options.pco.v[3] =
843 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
844 options.pco.v[4] = 0x01; /* Authenticate request */
845 options.pco.v[5] = 0x01;
846 options.pco.v[6] = 0x00; /* MSB of length */
847 options.pco.v[7] =
848 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
849 options.pco.v[8] = strlen(args_info.uid_arg);
850 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
851 options.pco.v[9 + strlen(args_info.uid_arg)] =
852 strlen(args_info.pwd_arg);
853 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
854 args_info.pwd_arg, strlen(args_info.pwd_arg));
855
856 /* createif */
857 options.createif = args_info.createif_flag;
858
859 /* net */
860 /* Store net as in_addr net and mask */
861 if (args_info.net_arg) {
862 if (ippool_aton
863 (&options.net, &options.mask, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100864 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100865 "Invalid network address: %s!",
866 args_info.net_arg);
867 exit(1);
868 }
jjakoc6762cf2004-04-28 14:52:58 +0000869#if defined (__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100870 options.netaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
871 options.destaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
jjakoc6762cf2004-04-28 14:52:58 +0000872#else
Harald Weltebed35df2011-11-02 13:06:18 +0100873 options.netaddr.s_addr = options.net.s_addr;
874 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000875#endif
876
Harald Weltebed35df2011-11-02 13:06:18 +0100877 } else {
878 options.net.s_addr = 0;
879 options.mask.s_addr = 0;
880 options.netaddr.s_addr = 0;
881 options.destaddr.s_addr = 0;
882 }
jjako193e8b12003-11-10 12:31:41 +0000883
Harald Weltebed35df2011-11-02 13:06:18 +0100884 /* ipup */
885 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000886
Harald Weltebed35df2011-11-02 13:06:18 +0100887 /* ipdown */
888 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000889
Harald Weltebed35df2011-11-02 13:06:18 +0100890 /* statedir */
891 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000892
Harald Weltebed35df2011-11-02 13:06:18 +0100893 /* defaultroute */
894 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000895
Harald Weltebed35df2011-11-02 13:06:18 +0100896 /* pinghost */
897 /* Store ping host as in_addr */
898 if (args_info.pinghost_arg) {
899 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100900 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100901 "Invalid ping host: %s!",
902 args_info.pinghost_arg);
903 return -1;
904 } else {
905 memcpy(&options.pinghost.s_addr, host->h_addr,
906 host->h_length);
907 printf("Using ping host: %s (%s)\n",
908 args_info.pinghost_arg,
909 inet_ntoa(options.pinghost));
910 }
911 }
jjakoa7cd2492003-04-11 09:40:12 +0000912
Harald Weltebed35df2011-11-02 13:06:18 +0100913 /* Other ping parameters */
914 options.pingrate = args_info.pingrate_arg;
915 options.pingsize = args_info.pingsize_arg;
916 options.pingcount = args_info.pingcount_arg;
917 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000918
Harald Weltebed35df2011-11-02 13:06:18 +0100919 /* norecovery */
920 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000921
Harald Weltebed35df2011-11-02 13:06:18 +0100922 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000923
924}
925
Harald Weltebed35df2011-11-02 13:06:18 +0100926int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
927{
928 unsigned int i;
929 printf("The packet looks like this:\n");
930 for (i = 0; i < len; i++) {
931 printf("%02x ", (unsigned char)*(char *)(pack + i));
932 if (!((i + 1) % 16))
933 printf("\n");
934 };
935 printf("\n");
936 return 0;
jjako52c24142002-12-16 13:33:51 +0000937}
938
Harald Weltebed35df2011-11-02 13:06:18 +0100939char *print_ipprot(int t)
940{
941 switch (t) {
942 case 1:
943 return "ICMP";
944 case 6:
945 return "TCP";
946 case 17:
947 return "UDP";
948 default:
949 return "Unknown";
950 };
jjako5da68452003-01-28 16:08:47 +0000951}
952
Harald Weltebed35df2011-11-02 13:06:18 +0100953char *print_icmptype(int t)
954{
955 static char *ttab[] = {
956 "Echo Reply",
957 "ICMP 1",
958 "ICMP 2",
959 "Dest Unreachable",
960 "Source Quench",
961 "Redirect",
962 "ICMP 6",
963 "ICMP 7",
964 "Echo",
965 "ICMP 9",
966 "ICMP 10",
967 "Time Exceeded",
968 "Parameter Problem",
969 "Timestamp",
970 "Timestamp Reply",
971 "Info Request",
972 "Info Reply"
973 };
974 if (t < 0 || t > 16)
975 return ("OUT-OF-RANGE");
976 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +0000977}
978
Harald Weltebed35df2011-11-02 13:06:18 +0100979int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
980{
981 unsigned int n;
982 uint64_t i64 = 0;
983 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
984 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +0000985
Harald Weltebed35df2011-11-02 13:06:18 +0100986 /* Convert to uint64_t from ul16_t format (most significant digit first) */
987 /* ul16_t format always starts with 0x91 to indicate international format */
988 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
989 for (n = 0; n < src->l; n++) {
990 if ((src->v[n] & 0x0f) != 0x0f) {
991 i64 *= 10;
992 i64 += src->v[n] & 0x0f;
993 }
994 if ((src->v[n] & 0xf0) != 0xf0) {
995 i64 *= 10;
996 i64 += (src->v[n] & 0xf0) >> 4;
997 }
998 }
jjako193e8b12003-11-10 12:31:41 +0000999
Harald Weltebed35df2011-11-02 13:06:18 +01001000 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001001
Harald Weltebed35df2011-11-02 13:06:18 +01001002 /* Generate array with least significant digit in first octet */
1003 while (i64) {
1004 msa[msalen++] = i64 % 10;
1005 i64 = i64 / 10;
1006 }
jjako193e8b12003-11-10 12:31:41 +00001007
Harald Weltebed35df2011-11-02 13:06:18 +01001008 /* Convert back to ul16_t format */
1009 for (n = 0; n < msalen; n++) {
1010 if ((n % 2) == 0) {
1011 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1012 dst->l += 1;
1013 } else {
1014 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1015 msa[msalen - n - 1] * 16;
1016 }
1017 }
jjako193e8b12003-11-10 12:31:41 +00001018
Harald Weltebed35df2011-11-02 13:06:18 +01001019 return 0;
jjako193e8b12003-11-10 12:31:41 +00001020
1021}
1022
Harald Weltebed35df2011-11-02 13:06:18 +01001023int imsi_add(uint64_t src, uint64_t * dst, int add)
1024{
1025 /* TODO: big endian / small endian ??? */
1026 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001027
Harald Weltebed35df2011-11-02 13:06:18 +01001028 /* Convert from uint64_t bcd to uint64_t integer format */
1029 /* The resulting integer format is multiplied by 10 */
1030 while (src) {
1031 if ((src & 0x0f) != 0x0f) {
1032 i64 *= 10;
1033 i64 += (src & 0x0f);
1034 }
1035 if ((src & 0xf0) != 0xf0) {
1036 i64 *= 10;
1037 i64 += (src & 0xf0) >> 4;
1038 }
1039 src = src >> 8;
1040 }
jjako193e8b12003-11-10 12:31:41 +00001041
Harald Weltebed35df2011-11-02 13:06:18 +01001042 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001043
Harald Weltebed35df2011-11-02 13:06:18 +01001044 *dst = 0;
1045 while (i64) {
1046 *dst = *dst << 4;
1047 *dst += (i64 % 10);
1048 i64 = i64 / 10;
1049 }
jjako193e8b12003-11-10 12:31:41 +00001050
Harald Weltebed35df2011-11-02 13:06:18 +01001051 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001052
Harald Weltebed35df2011-11-02 13:06:18 +01001053 return 0;
jjako193e8b12003-11-10 12:31:41 +00001054
1055}
1056
jjakoafb2a972003-01-29 21:04:13 +00001057/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001058int ping_timeout(struct timeval *tp)
1059{
1060 struct timezone tz;
1061 struct timeval tv;
1062 int diff;
1063 if ((options.pinghost.s_addr) && (2 == state) &&
1064 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1065 gettimeofday(&tv, &tz);
1066 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1067 tp->tv_sec = 0;
1068 if (diff > 0)
1069 tp->tv_usec = diff;
1070 else {
1071 /* For some reason we get packet loss if set to zero */
1072 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1073 tp->tv_usec = 0;
1074 }
1075 }
1076 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001077}
1078
jjako5da68452003-01-28 16:08:47 +00001079/* Print out statistics when at the end of ping sequence */
1080int ping_finish()
1081{
Harald Weltebed35df2011-11-02 13:06:18 +01001082 struct timezone tz;
1083 struct timeval tv;
1084 int elapsed;
1085 gettimeofday(&tv, &tz);
1086 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1087 printf("\n");
1088 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1089 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1090 elapsed / 1000000.0);
1091 printf("%d packets received, ", nreceived);
1092 if (ntransmitted) {
1093 if (nreceived > ntransmitted)
1094 printf("-- somebody's printing up packets!");
1095 else
1096 printf("%d%% packet loss",
1097 (int)(((ntransmitted - nreceived) * 100) /
1098 ntransmitted));
1099 }
1100 printf("\n");
1101 if (options.debug)
1102 printf("%d packets received in total\n", ntreceived);
1103 if (nreceived && tsum)
1104 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1105 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1106 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001107
Harald Weltebed35df2011-11-02 13:06:18 +01001108 ntransmitted = 0;
1109 return 0;
jjako5da68452003-01-28 16:08:47 +00001110}
1111
1112/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001113int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1114{
1115 struct timezone tz;
1116 struct timeval tv;
1117 struct timeval *tp;
1118 struct ip_ping *pingpack = pack;
1119 struct in_addr src;
1120 int triptime;
jjako5da68452003-01-28 16:08:47 +00001121
Harald Weltebed35df2011-11-02 13:06:18 +01001122 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001123
Harald Weltebed35df2011-11-02 13:06:18 +01001124 gettimeofday(&tv, &tz);
1125 if (options.debug)
1126 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001127
Harald Weltebed35df2011-11-02 13:06:18 +01001128 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1129 printf("packet too short (%d bytes) from %s\n", len,
1130 inet_ntoa(src));
1131 return 0;
1132 }
jjako5da68452003-01-28 16:08:47 +00001133
Harald Weltebed35df2011-11-02 13:06:18 +01001134 ntreceived++;
1135 if (pingpack->protocol != 1) {
1136 if (!options.pingquiet)
1137 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1138 len, inet_ntoa(src), pingpack->protocol,
1139 print_ipprot(pingpack->protocol));
1140 return 0;
1141 }
jjako5da68452003-01-28 16:08:47 +00001142
Harald Weltebed35df2011-11-02 13:06:18 +01001143 if (pingpack->type != 0) {
1144 if (!options.pingquiet)
1145 printf
1146 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1147 len, inet_ntoa(src), pingpack->type,
1148 print_icmptype(pingpack->type), pingpack->code);
1149 return 0;
1150 }
jjako5da68452003-01-28 16:08:47 +00001151
Harald Weltebed35df2011-11-02 13:06:18 +01001152 nreceived++;
1153 if (!options.pingquiet)
1154 printf("%d bytes from %s: icmp_seq=%d", len,
1155 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001156
Harald Weltebed35df2011-11-02 13:06:18 +01001157 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1158 gettimeofday(&tv, &tz);
1159 tp = (struct timeval *)pingpack->data;
1160 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1161 tv.tv_sec--;
1162 tv.tv_usec += 1000000;
1163 }
1164 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001165
Harald Weltebed35df2011-11-02 13:06:18 +01001166 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1167 tsum += triptime;
1168 if (triptime < tmin)
1169 tmin = triptime;
1170 if (triptime > tmax)
1171 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001172
Harald Weltebed35df2011-11-02 13:06:18 +01001173 if (!options.pingquiet)
1174 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001175
Harald Weltebed35df2011-11-02 13:06:18 +01001176 } else if (!options.pingquiet)
1177 printf("\n");
1178 return 0;
jjako5da68452003-01-28 16:08:47 +00001179}
1180
1181/* Create a new ping packet and send it off to peer. */
1182int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001183 struct in_addr *dst, int seq, unsigned int datasize)
1184{
jjako5da68452003-01-28 16:08:47 +00001185
Harald Weltebed35df2011-11-02 13:06:18 +01001186 struct ip_ping pack;
1187 uint16_t *p = (uint16_t *) & pack;
1188 uint8_t *p8 = (uint8_t *) & pack;
1189 struct in_addr src;
1190 unsigned int n;
1191 long int sum = 0;
1192 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001193
Harald Weltebed35df2011-11-02 13:06:18 +01001194 struct timezone tz;
1195 struct timeval *tp =
1196 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001197
Harald Weltebed35df2011-11-02 13:06:18 +01001198 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001199 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001200 "Ping size to large: %d!", datasize);
1201 return -1;
1202 }
jjako5da68452003-01-28 16:08:47 +00001203
Harald Weltebed35df2011-11-02 13:06:18 +01001204 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001205
Harald Weltebed35df2011-11-02 13:06:18 +01001206 pack.ipver = 0x45;
1207 pack.tos = 0x00;
1208 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1209 pack.fragid = 0x0000;
1210 pack.offset = 0x0040;
1211 pack.ttl = 0x40;
1212 pack.protocol = 0x01;
1213 pack.ipcheck = 0x0000;
1214 pack.src = src.s_addr;
1215 pack.dst = dst->s_addr;
1216 pack.type = 0x08;
1217 pack.code = 0x00;
1218 pack.checksum = 0x0000;
1219 pack.ident = 0x0000;
1220 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001221
Harald Weltebed35df2011-11-02 13:06:18 +01001222 /* Generate ICMP payload */
1223 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1224 for (n = 0; n < (datasize); n++)
1225 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001226
Harald Weltebed35df2011-11-02 13:06:18 +01001227 if (datasize >= sizeof(struct timeval))
1228 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001229
Harald Weltebed35df2011-11-02 13:06:18 +01001230 /* Calculate IP header checksum */
1231 p = (uint16_t *) & pack;
1232 count = CREATEPING_IP;
1233 sum = 0;
1234 while (count > 1) {
1235 sum += *p++;
1236 count -= 2;
1237 }
1238 while (sum >> 16)
1239 sum = (sum & 0xffff) + (sum >> 16);
1240 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001241
Harald Weltebed35df2011-11-02 13:06:18 +01001242 /* Calculate ICMP checksum */
1243 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1244 sum = 0;
1245 p = (uint16_t *) & pack;
1246 p += CREATEPING_IP / 2;
1247 while (count > 1) {
1248 sum += *p++;
1249 count -= 2;
1250 }
1251 if (count > 0)
1252 sum += *(unsigned char *)p;
1253 while (sum >> 16)
1254 sum = (sum & 0xffff) + (sum >> 16);
1255 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001256
Harald Weltebed35df2011-11-02 13:06:18 +01001257 ntransmitted++;
1258 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001259}
1260
Harald Weltebed35df2011-11-02 13:06:18 +01001261int delete_context(struct pdp_t *pdp)
1262{
1263
1264 if (tun && options.ipdown)
1265 tun_runscript(tun, options.ipdown);
1266
1267 ipdel((struct iphash_t *)pdp->peer);
1268 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1269
1270 if (1 == options.contexts)
1271 state = 5; /* Disconnected */
1272
1273 return 0;
1274}
jjakoa7cd2492003-04-11 09:40:12 +00001275
1276/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001277int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1278{
1279 struct iphash_t *ipm;
1280 struct in_addr src;
1281 struct tun_packet_t *iph = (struct tun_packet_t *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001282
Harald Weltebed35df2011-11-02 13:06:18 +01001283 src.s_addr = iph->src;
jjakoa7cd2492003-04-11 09:40:12 +00001284
Harald Weltebed35df2011-11-02 13:06:18 +01001285 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001286 printf("Dropping packet from invalid source address: %s\n",
1287 inet_ntoa(src));
Harald Weltebed35df2011-11-02 13:06:18 +01001288 return 0;
1289 }
1290
1291 if (ipm->pdp) /* Check if a peer protocol is defined */
1292 gtp_data_req(gsn, ipm->pdp, pack, len);
1293 return 0;
jjako52c24142002-12-16 13:33:51 +00001294}
1295
Harald Weltebed35df2011-11-02 13:06:18 +01001296int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1297{
1298 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +00001299
Harald Weltebed35df2011-11-02 13:06:18 +01001300 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001301
Harald Weltebed35df2011-11-02 13:06:18 +01001302 if (cause < 0) {
1303 printf("Create PDP Context Request timed out\n");
1304 if (iph->pdp->version == 1) {
1305 printf("Retrying with version 0\n");
1306 iph->pdp->version = 0;
1307 gtp_create_context_req(gsn, iph->pdp, iph);
1308 return 0;
1309 } else {
1310 state = 0;
1311 pdp_freepdp(iph->pdp);
1312 iph->pdp = NULL;
1313 return EOF;
1314 }
1315 }
jjako2c381332003-10-21 19:09:53 +00001316
Harald Weltebed35df2011-11-02 13:06:18 +01001317 if (cause != 128) {
1318 printf
1319 ("Received create PDP context response. Cause value: %d\n",
1320 cause);
1321 state = 0;
1322 pdp_freepdp(iph->pdp);
1323 iph->pdp = NULL;
1324 return EOF; /* Not what we expected */
1325 }
jjako52c24142002-12-16 13:33:51 +00001326
Harald Weltebed35df2011-11-02 13:06:18 +01001327 if (pdp_euaton(&pdp->eua, &addr)) {
1328 printf
1329 ("Received create PDP context response. Cause value: %d\n",
1330 cause);
1331 pdp_freepdp(iph->pdp);
1332 iph->pdp = NULL;
1333 state = 0;
1334 return EOF; /* Not a valid IP address */
1335 }
jjakoa7cd2492003-04-11 09:40:12 +00001336
Harald Weltebed35df2011-11-02 13:06:18 +01001337 printf("Received create PDP context response. IP address: %s\n",
1338 inet_ntoa(addr));
jjakoa7cd2492003-04-11 09:40:12 +00001339
Harald Weltebed35df2011-11-02 13:06:18 +01001340 if ((options.createif) && (!options.net.s_addr)) {
1341 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +00001342#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +01001343 inet_aton("255.255.255.255", &m);
jjako1d3db972004-01-16 09:56:56 +00001344#else
Harald Weltebed35df2011-11-02 13:06:18 +01001345 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +00001346#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001347 /* printf("Setting up interface and routing\n"); */
1348 tun_addaddr(tun, &addr, &addr, &m);
1349 if (options.defaultroute) {
1350 struct in_addr rm;
1351 rm.s_addr = 0;
1352 tun_addroute(tun, &rm, &addr, &rm);
1353 }
1354 if (options.ipup)
1355 tun_runscript(tun, options.ipup);
1356 }
jjako52c24142002-12-16 13:33:51 +00001357
Harald Weltebed35df2011-11-02 13:06:18 +01001358 ipset((struct iphash_t *)pdp->peer, &addr);
1359
1360 state = 2; /* Connected */
1361
1362 return 0;
jjako52c24142002-12-16 13:33:51 +00001363}
1364
Harald Weltebed35df2011-11-02 13:06:18 +01001365int delete_pdp_conf(struct pdp_t *pdp, int cause)
1366{
1367 printf("Received delete PDP context response. Cause value: %d\n",
1368 cause);
1369 return 0;
jjako52c24142002-12-16 13:33:51 +00001370}
1371
Harald Weltebed35df2011-11-02 13:06:18 +01001372int echo_conf(int recovery)
1373{
jjako91aaf222003-10-22 10:09:32 +00001374
Harald Weltebed35df2011-11-02 13:06:18 +01001375 if (recovery < 0) {
1376 printf("Echo Request timed out\n");
1377 if (echoversion == 1) {
1378 printf("Retrying with version 0\n");
1379 echoversion = 0;
1380 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1381 return 0;
1382 } else {
1383 state = 0;
1384 return EOF;
1385 }
1386 } else {
1387 printf("Received echo response\n");
1388 if (!options.contexts)
1389 state = 5;
1390 }
1391 return 0;
jjako52c24142002-12-16 13:33:51 +00001392}
1393
Harald Weltebed35df2011-11-02 13:06:18 +01001394int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1395{
1396 /* if (cause < 0) return 0; Some error occurred. We don't care */
1397 switch (type) {
1398 case GTP_ECHO_REQ:
1399 return echo_conf(cause);
1400 case GTP_CREATE_PDP_REQ:
1401 return create_pdp_conf(pdp, cbp, cause);
1402 case GTP_DELETE_PDP_REQ:
1403 if (cause != 128)
1404 return 0; /* Request not accepted. We don't care */
1405 return delete_pdp_conf(pdp, cause);
1406 default:
1407 return 0;
1408 }
jjako52c24142002-12-16 13:33:51 +00001409}
1410
Harald Weltebed35df2011-11-02 13:06:18 +01001411int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1412{
1413 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1414 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001415}
1416
1417int main(int argc, char **argv)
1418{
Harald Weltebed35df2011-11-02 13:06:18 +01001419 fd_set fds; /* For select() */
1420 struct timeval idleTime; /* How long to select() */
1421 struct pdp_t *pdp;
1422 int n;
1423 int starttime = time(NULL); /* Time program was started */
1424 int stoptime = 0; /* Time to exit */
1425 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001426 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001427
Harald Weltebed35df2011-11-02 13:06:18 +01001428 struct timezone tz; /* Used for calculating ping times */
1429 struct timeval tv;
1430 int diff;
jjako52c24142002-12-16 13:33:51 +00001431
bjovana8f71eb2017-02-24 17:39:20 +01001432 signal(SIGTERM, signal_handler);
1433 signal(SIGHUP, signal_handler);
1434 signal(SIGINT, signal_handler);
1435
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001436 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001437
Harald Weltebed35df2011-11-02 13:06:18 +01001438 /* Process options given in configuration file and command line */
1439 if (process_options(argc, argv))
1440 exit(1);
jjako52c24142002-12-16 13:33:51 +00001441
Harald Weltebed35df2011-11-02 13:06:18 +01001442 printf("\nInitialising GTP library\n");
1443 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001444 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001445 exit(1);
1446 }
1447 if (gsn->fd0 > maxfd)
1448 maxfd = gsn->fd0;
1449 if (gsn->fd1c > maxfd)
1450 maxfd = gsn->fd1c;
1451 if (gsn->fd1u > maxfd)
1452 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001453
Harald Weltebed35df2011-11-02 13:06:18 +01001454 gtp_set_cb_delete_context(gsn, delete_context);
1455 gtp_set_cb_conf(gsn, conf);
1456 if (options.createif)
1457 gtp_set_cb_data_ind(gsn, encaps_tun);
1458 else
1459 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001460
Harald Weltebed35df2011-11-02 13:06:18 +01001461 if (options.createif) {
1462 printf("Setting up interface\n");
1463 /* Create a tunnel interface */
1464 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001465 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001466 "Failed to create tun");
1467 exit(1);
1468 }
1469 tun_set_cb_ind(tun, cb_tun_ind);
1470 if (tun->fd > maxfd)
1471 maxfd = tun->fd;
1472 }
jjakoa7cd2492003-04-11 09:40:12 +00001473
Harald Weltebed35df2011-11-02 13:06:18 +01001474 if ((options.createif) && (options.net.s_addr)) {
1475 /* printf("Setting up interface and routing\n"); */
1476 tun_addaddr(tun, &options.netaddr, &options.destaddr,
1477 &options.mask);
1478 if (options.defaultroute) {
1479 struct in_addr rm;
1480 rm.s_addr = 0;
1481 tun_addroute(tun, &rm, &options.destaddr, &rm);
1482 }
1483 if (options.ipup)
1484 tun_runscript(tun, options.ipup);
1485 }
jjakoa7cd2492003-04-11 09:40:12 +00001486
Harald Weltebed35df2011-11-02 13:06:18 +01001487 /* Initialise hash tables */
1488 memset(&iphash, 0, sizeof(iphash));
1489 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001490
Harald Weltebed35df2011-11-02 13:06:18 +01001491 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001492
Harald Weltebed35df2011-11-02 13:06:18 +01001493 /* See if anybody is there */
1494 printf("Sending off echo request\n");
1495 echoversion = options.gtpversion;
1496 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001497
Harald Weltebed35df2011-11-02 13:06:18 +01001498 for (n = 0; n < options.contexts; n++) {
1499 uint64_t myimsi;
1500 printf("Setting up PDP context #%d\n", n);
1501 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001502
Harald Weltebed35df2011-11-02 13:06:18 +01001503 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001504
Harald Weltebed35df2011-11-02 13:06:18 +01001505 /* Allocated here. */
1506 /* If create context failes we have to deallocate ourselves. */
1507 /* Otherwise it is deallocated by gtplib */
1508 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001509
Harald Weltebed35df2011-11-02 13:06:18 +01001510 pdp->peer = &iparr[n];
1511 pdp->ipif = tun; /* TODO */
1512 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001513
Harald Weltebed35df2011-11-02 13:06:18 +01001514 if (options.gtpversion == 0) {
1515 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001516 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001517 "QoS length too big");
1518 exit(1);
1519 } else {
1520 memcpy(pdp->qos_req0, options.qos.v,
1521 options.qos.l);
1522 }
1523 }
jjakoa7cd2492003-04-11 09:40:12 +00001524
Harald Weltebed35df2011-11-02 13:06:18 +01001525 pdp->qos_req.l = options.qos.l;
1526 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001527
Harald Weltebed35df2011-11-02 13:06:18 +01001528 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001529
Harald Weltebed35df2011-11-02 13:06:18 +01001530 pdp->rattype.l = options.rattype.l;
1531 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1532 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001533
Harald Weltebed35df2011-11-02 13:06:18 +01001534 pdp->userloc.l = options.userloc.l;
1535 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1536 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001537
Harald Weltebed35df2011-11-02 13:06:18 +01001538 pdp->rai.l = options.rai.l;
1539 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1540 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001541
Harald Weltebed35df2011-11-02 13:06:18 +01001542 pdp->mstz.l = options.mstz.l;
1543 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1544 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001545
Harald Weltebed35df2011-11-02 13:06:18 +01001546 pdp->imeisv.l = options.imeisv.l;
1547 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1548 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001549
Harald Weltebed35df2011-11-02 13:06:18 +01001550 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001553 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001554 "APN length too big");
1555 exit(1);
1556 } else {
1557 pdp->apn_use.l = options.apn.l;
1558 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1559 }
jjako193e8b12003-11-10 12:31:41 +00001560
Harald Weltebed35df2011-11-02 13:06:18 +01001561 pdp->gsnlc.l = sizeof(options.listen);
1562 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1563 pdp->gsnlu.l = sizeof(options.listen);
1564 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001565
Harald Weltebed35df2011-11-02 13:06:18 +01001566 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001567 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001568 "MSISDN length too big");
1569 exit(1);
1570 } else {
1571 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1572 }
jjakob62c3dd2004-05-27 18:51:55 +00001573
Harald Weltebed35df2011-11-02 13:06:18 +01001574 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
jjako52c24142002-12-16 13:33:51 +00001575
Harald Weltebed35df2011-11-02 13:06:18 +01001576 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001577 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001578 "PCO length too big");
1579 exit(1);
1580 } else {
1581 pdp->pco_req.l = options.pco.l;
1582 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1583 }
jjako52c24142002-12-16 13:33:51 +00001584
Harald Weltebed35df2011-11-02 13:06:18 +01001585 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001586
Harald Weltebed35df2011-11-02 13:06:18 +01001587 pdp->hisaddr0 = options.remote;
1588 pdp->hisaddr1 = options.remote;
1589
1590 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1591 512 = Flat rate, 256 = Hot billing */
1592
1593 /* Create context */
1594 /* We send this of once. Retransmissions are handled by gtplib */
1595 gtp_create_context_req(gsn, pdp, &iparr[n]);
1596 }
1597
1598 state = 1; /* Enter wait_connection state */
1599
1600 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001601
jjako52c24142002-12-16 13:33:51 +00001602 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001603 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001604 /******************************************************************/
1605
Harald Weltebed35df2011-11-02 13:06:18 +01001606 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001607
Harald Weltebed35df2011-11-02 13:06:18 +01001608 /* Take down client after timeout after disconnect */
1609 if ((4 == state) && ((stoptime) <= time(NULL))) {
1610 state = 5;
1611 }
jjako7b8fad42003-07-07 14:37:42 +00001612
Harald Weltebed35df2011-11-02 13:06:18 +01001613 /* Take down client after timelimit timeout */
1614 if ((2 == state) && (options.timelimit) &&
1615 ((starttime + options.timelimit) <= time(NULL))) {
1616 state = 3;
1617 }
jjako7b8fad42003-07-07 14:37:42 +00001618
Harald Weltebed35df2011-11-02 13:06:18 +01001619 /* Take down client after ping timeout */
1620 if ((2 == state) && (pingtimeout)
1621 && (pingtimeout <= time(NULL))) {
1622 state = 3;
1623 }
jjako7b8fad42003-07-07 14:37:42 +00001624
Harald Weltebed35df2011-11-02 13:06:18 +01001625 /* Set pingtimeout for later disconnection */
1626 if (options.pingcount && ntransmitted >= options.pingcount) {
1627 pingtimeout = time(NULL) + 5; /* Extra seconds */
1628 }
jjako7b8fad42003-07-07 14:37:42 +00001629
Harald Weltebed35df2011-11-02 13:06:18 +01001630 /* Print statistics if no more ping packets are missing */
1631 if (ntransmitted && options.pingcount
1632 && nreceived >= options.pingcount) {
1633 ping_finish();
1634 if (!options.createif)
1635 state = 3;
1636 }
jjako7b8fad42003-07-07 14:37:42 +00001637
Harald Weltebed35df2011-11-02 13:06:18 +01001638 /* Send off disconnect */
1639 if (3 == state) {
1640 state = 4;
1641 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1642 for (n = 0; n < options.contexts; n++) {
1643 /* Delete context */
1644 printf("Disconnecting PDP context #%d\n", n);
1645 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1646 1);
1647 if ((options.pinghost.s_addr != 0)
1648 && ntransmitted)
1649 ping_finish();
1650 }
1651 }
jjako7b8fad42003-07-07 14:37:42 +00001652
Harald Weltebed35df2011-11-02 13:06:18 +01001653 /* Send of ping packets */
1654 diff = 0;
1655 while ((diff <= 0) &&
1656 /* Send off an ICMP ping packet */
1657 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1658 ((pingseq < options.pingcount)
1659 || (options.pingcount == 0))) {
1660 if (!pingseq)
1661 gettimeofday(&firstping, &tz); /* Set time of first ping */
1662 gettimeofday(&tv, &tz);
1663 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1664 if (diff <= 0) {
1665 if (options.debug)
1666 printf("Create_ping %d\n", diff);
1667 create_ping(gsn,
1668 iparr[pingseq %
1669 options.contexts].pdp,
1670 &options.pinghost, pingseq,
1671 options.pingsize);
1672 pingseq++;
1673 }
1674 }
jjako5da68452003-01-28 16:08:47 +00001675
Harald Weltebed35df2011-11-02 13:06:18 +01001676 FD_ZERO(&fds);
1677 if (tun)
1678 FD_SET(tun->fd, &fds);
1679 FD_SET(gsn->fd0, &fds);
1680 FD_SET(gsn->fd1c, &fds);
1681 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001682
Harald Weltebed35df2011-11-02 13:06:18 +01001683 gtp_retranstimeout(gsn, &idleTime);
1684 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001685
Harald Weltebed35df2011-11-02 13:06:18 +01001686 if (options.debug)
1687 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1688 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001689
bjovana8f71eb2017-02-24 17:39:20 +01001690 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001691 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1692 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001693 if (errno == EINTR)
1694 signal_received = 1;
1695 else
1696 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1697 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001698 break;
1699 case 0:
1700 gtp_retrans(gsn); /* Only retransmit if nothing else */
1701 break;
1702 default:
1703 break;
1704 }
1705
bjovana8f71eb2017-02-24 17:39:20 +01001706 if (!signal_received) {
1707
1708 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1709 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1710 "TUN decaps failed");
1711 }
1712
1713 if (FD_ISSET(gsn->fd0, &fds))
1714 gtp_decaps0(gsn);
1715
1716 if (FD_ISSET(gsn->fd1c, &fds))
1717 gtp_decaps1c(gsn);
1718
1719 if (FD_ISSET(gsn->fd1u, &fds))
1720 gtp_decaps1u(gsn);
1721
Harald Weltebed35df2011-11-02 13:06:18 +01001722 }
Harald Weltebed35df2011-11-02 13:06:18 +01001723 }
1724
1725 gtp_free(gsn); /* Clean up the gsn instance */
1726
1727 if (options.createif)
1728 tun_free(tun);
1729
1730 if (0 == state)
1731 exit(1); /* Indicate error */
1732
1733 return 0;
jjako52c24142002-12-16 13:33:51 +00001734}