blob: 4cc202101da6ad370d6500d482662412e5cbdef1 [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.
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>
Harald Welte63ebccd2017-08-02 21:10:09 +020032#include <netinet/ip.h>
jjako52c24142002-12-16 13:33:51 +000033#include <arpa/inet.h>
34#include <sys/wait.h>
35#include <sys/stat.h>
36#include <unistd.h>
37#include <sys/socket.h>
38#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000039#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000040#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000041#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000042#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000043#include <resolv.h>
44#include <time.h>
45
jjakoff9985c2004-01-16 11:05:22 +000046#include "config.h"
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020047#include "../lib/tun.h"
48#include "../lib/ippool.h"
49#include "../lib/syserr.h"
jjako52c24142002-12-16 13:33:51 +000050#include "../gtp/pdp.h"
51#include "../gtp/gtp.h"
52#include "cmdline.h"
53
Harald Weltebed35df2011-11-02 13:06:18 +010054#define IPADDRLEN 256 /* Character length of addresses */
55#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000056
jjakoa7cd2492003-04-11 09:40:12 +000057/* HASH tables for IP address allocation */
58struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010059 uint8_t inuse; /* 0=free. 1=used by somebody */
60 struct iphash_t *ipnext;
61 struct pdp_t *pdp;
Harald Welted12eab92017-08-02 19:49:47 +020062 struct in46_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000063};
64struct iphash_t iparr[MAXCONTEXTS];
65struct iphash_t *iphash[MAXCONTEXTS];
66
67/* State variable used for ping */
68/* 0: Idle */
69/* 1: Wait_connect */
70/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000071/* 3: Done */
72/* 4: Wait_disconnect */
73/* 5: Disconnected */
bjovana8f71eb2017-02-24 17:39:20 +010074volatile sig_atomic_t state = 0;
jjako52c24142002-12-16 13:33:51 +000075
Harald Weltebed35df2011-11-02 13:06:18 +010076struct gsn_t *gsn = NULL; /* GSN instance */
77struct tun_t *tun = NULL; /* TUN instance */
78int maxfd = 0; /* For select() */
79int echoversion = 1; /* First try this version */
jjako52c24142002-12-16 13:33:51 +000080
jjakoa7cd2492003-04-11 09:40:12 +000081/* Struct with local versions of gengetopt options */
82struct {
Harald Weltebed35df2011-11-02 13:06:18 +010083 int debug; /* Print debug messages */
84 int createif; /* Create local network interface */
Harald Welted12eab92017-08-02 19:49:47 +020085 struct in_addr netaddr, destaddr, net; /* Network interface */
86 size_t prefixlen;
Harald Weltebed35df2011-11-02 13:06:18 +010087 char *ipup, *ipdown; /* Filename of scripts */
88 int defaultroute; /* Set up default route */
89 struct in_addr pinghost; /* Remote ping host */
90 int pingrate;
91 int pingsize;
92 int pingcount;
93 int pingquiet;
94 struct in_addr listen;
95 struct in_addr remote;
96 struct in_addr dns;
97 int contexts; /* Number of contexts to create */
98 int timelimit; /* Number of seconds to be connected */
99 char *statedir;
100 uint64_t imsi;
101 uint8_t nsapi;
102 int gtpversion;
103 struct ul255_t pco;
104 struct ul255_t qos;
105 uint16_t cch;
106 struct ul255_t apn;
107 uint8_t selmode;
108 struct ul255_t rattype;
109 int rattype_given;
110 struct ul255_t userloc;
111 int userloc_given;
112 struct ul255_t rai;
113 int rai_given;
114 struct ul255_t mstz;
115 int mstz_given;
116 struct ul255_t imeisv;
117 int imeisv_given;
118 struct ul16_t msisdn;
119 int norecovery_given;
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800120 int tx_gpdu_seq;
jjakoa7cd2492003-04-11 09:40:12 +0000121} options;
jjako52c24142002-12-16 13:33:51 +0000122
jjako5da68452003-01-28 16:08:47 +0000123/* Definitions to use for PING. Most of the ping code was derived from */
124/* the original ping program by Mike Muuss */
125
126/* IP header and ICMP echo header */
127#define CREATEPING_MAX 2048
128#define CREATEPING_IP 20
129#define CREATEPING_ICMP 8
130
131struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100132 uint8_t ipver; /* Type and header length */
133 uint8_t tos; /* Type of Service */
134 uint16_t length; /* Total length */
135 uint16_t fragid; /* Identifier */
136 uint16_t offset; /* Flags and fragment offset */
137 uint8_t ttl; /* Time to live */
138 uint8_t protocol; /* Protocol */
139 uint16_t ipcheck; /* Header checksum */
140 uint32_t src; /* Source address */
141 uint32_t dst; /* Destination */
142 uint8_t type; /* Type and header length */
143 uint8_t code; /* Code */
144 uint16_t checksum; /* Header checksum */
145 uint16_t ident; /* Identifier */
146 uint16_t seq; /* Sequence number */
147 uint8_t data[CREATEPING_MAX]; /* Data */
148} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000149
150/* Statistical values for ping */
151int nreceived = 0;
152int ntreceived = 0;
153int ntransmitted = 0;
154int tmin = 999999999;
155int tmax = 0;
156int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100157int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000158struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000159
bjovana8f71eb2017-02-24 17:39:20 +0100160void signal_handler(int signo)
161{
162 if (state == 2)
163 state = 3; /* Tell main loop to finish. */
164}
165
Harald Welted12eab92017-08-02 19:49:47 +0200166int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100167{
Harald Welted12eab92017-08-02 19:49:47 +0200168 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100169 struct iphash_t *h;
170 struct iphash_t *prev = NULL;
171 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200172 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100173 for (h = iphash[hash]; h; h = h->ipnext)
174 prev = h;
175 if (!prev)
176 iphash[hash] = ipaddr;
177 else
178 prev->ipnext = ipaddr;
179 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000180}
181
Harald Weltebed35df2011-11-02 13:06:18 +0100182int ipdel(struct iphash_t *ipaddr)
183{
Harald Welted12eab92017-08-02 19:49:47 +0200184 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100185 struct iphash_t *h;
186 struct iphash_t *prev = NULL;
187 for (h = iphash[hash]; h; h = h->ipnext) {
188 if (h == ipaddr) {
189 if (!prev)
190 iphash[hash] = h->ipnext;
191 else
192 prev->ipnext = h->ipnext;
193 return 0;
194 }
195 prev = h;
196 }
197 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000198}
199
Harald Welted12eab92017-08-02 19:49:47 +0200200int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100201{
Harald Welted12eab92017-08-02 19:49:47 +0200202 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100203 struct iphash_t *h;
204 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200205 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100206 *ipaddr = h;
207 return 0;
208 }
209 }
210 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000211}
212
jjakoa7cd2492003-04-11 09:40:12 +0000213/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +0100214void log_pid(char *pidfile)
215{
216 FILE *file;
217 mode_t oldmask;
218
219 oldmask = umask(022);
220 file = fopen(pidfile, "w");
221 umask(oldmask);
222 if (!file)
223 return;
224 fprintf(file, "%d\n", (int)getpid());
225 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000226}
227
Harald Weltebed35df2011-11-02 13:06:18 +0100228int process_options(int argc, char **argv)
229{
230 /* gengeopt declarations */
231 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000232
Harald Weltebed35df2011-11-02 13:06:18 +0100233 struct hostent *host;
234 unsigned int n;
235 uint16_t i;
236 uint8_t a;
237 uint8_t b;
238 char *tmp;
239 char *pch;
240 char *type;
241 char *mcc;
242 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100243 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100244 char *lac;
245 int lac_d;
246 char *rest;
247 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
248 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
249 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
250 int sign;
251 int nbquarters;
252 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000253
Harald Weltebed35df2011-11-02 13:06:18 +0100254 if (cmdline_parser(argc, argv, &args_info) != 0)
255 return -1;
256 if (args_info.debug_flag) {
257 if (args_info.remote_arg)
258 printf("remote: %s\n", args_info.remote_arg);
259 if (args_info.listen_arg)
260 printf("listen: %s\n", args_info.listen_arg);
261 if (args_info.conf_arg)
262 printf("conf: %s\n", args_info.conf_arg);
263 printf("debug: %d\n", args_info.debug_flag);
264 if (args_info.imsi_arg)
265 printf("imsi: %s\n", args_info.imsi_arg);
266 printf("qos: %#08x\n", args_info.qos_arg);
267 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
268 printf("qose2: %#04x\n", args_info.qose2_arg);
269 printf("qose3: %#06x\n", args_info.qose3_arg);
270 printf("qose4: %#06x\n", args_info.qose4_arg);
271 printf("charging: %#04x\n", args_info.charging_arg);
272 if (args_info.apn_arg)
273 printf("apn: %s\n", args_info.apn_arg);
274 if (args_info.msisdn_arg)
275 printf("msisdn: %s\n", args_info.msisdn_arg);
276 if (args_info.uid_arg)
277 printf("uid: %s\n", args_info.uid_arg);
278 if (args_info.pwd_arg)
279 printf("pwd: %s\n", args_info.pwd_arg);
280 if (args_info.pidfile_arg)
281 printf("pidfile: %s\n", args_info.pidfile_arg);
282 if (args_info.statedir_arg)
283 printf("statedir: %s\n", args_info.statedir_arg);
284 if (args_info.dns_arg)
285 printf("dns: %s\n", args_info.dns_arg);
286 printf("contexts: %d\n", args_info.contexts_arg);
287 printf("timelimit: %d\n", args_info.timelimit_arg);
288 printf("createif: %d\n", args_info.createif_flag);
289 if (args_info.ipup_arg)
290 printf("ipup: %s\n", args_info.ipup_arg);
291 if (args_info.ipdown_arg)
292 printf("ipdown: %s\n", args_info.ipdown_arg);
293 printf("defaultroute: %d\n", args_info.defaultroute_flag);
294 if (args_info.pinghost_arg)
295 printf("pinghost: %s\n", args_info.pinghost_arg);
296 printf("pingrate: %d\n", args_info.pingrate_arg);
297 printf("pingsize: %d\n", args_info.pingsize_arg);
298 printf("pingcount: %d\n", args_info.pingcount_arg);
299 printf("pingquiet: %d\n", args_info.pingquiet_flag);
300 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800301 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100302 }
jjakoa7cd2492003-04-11 09:40:12 +0000303
Harald Weltebed35df2011-11-02 13:06:18 +0100304 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000305
Harald Weltebed35df2011-11-02 13:06:18 +0100306 if (args_info.conf_arg) {
307 if (cmdline_parser_configfile
308 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
309 return -1;
310 if (args_info.debug_flag) {
311 printf("cmdline_parser_configfile\n");
312 if (args_info.remote_arg)
313 printf("remote: %s\n", args_info.remote_arg);
314 if (args_info.listen_arg)
315 printf("listen: %s\n", args_info.listen_arg);
316 if (args_info.conf_arg)
317 printf("conf: %s\n", args_info.conf_arg);
318 printf("debug: %d\n", args_info.debug_flag);
319 if (args_info.imsi_arg)
320 printf("imsi: %s\n", args_info.imsi_arg);
321 printf("qos: %#08x\n", args_info.qos_arg);
322 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
323 printf("qose2: %#04x\n", args_info.qose2_arg);
324 printf("qose3: %#06x\n", args_info.qose3_arg);
325 printf("qose4: %#06x\n", args_info.qose4_arg);
326 printf("charging: %#04x\n", args_info.charging_arg);
327 if (args_info.apn_arg)
328 printf("apn: %s\n", args_info.apn_arg);
329 if (args_info.msisdn_arg)
330 printf("msisdn: %s\n", args_info.msisdn_arg);
331 if (args_info.uid_arg)
332 printf("uid: %s\n", args_info.uid_arg);
333 if (args_info.pwd_arg)
334 printf("pwd: %s\n", args_info.pwd_arg);
335 if (args_info.pidfile_arg)
336 printf("pidfile: %s\n", args_info.pidfile_arg);
337 if (args_info.statedir_arg)
338 printf("statedir: %s\n",
339 args_info.statedir_arg);
340 if (args_info.dns_arg)
341 printf("dns: %s\n", args_info.dns_arg);
342 printf("contexts: %d\n", args_info.contexts_arg);
343 printf("timelimit: %d\n", args_info.timelimit_arg);
344 printf("createif: %d\n", args_info.createif_flag);
345 if (args_info.ipup_arg)
346 printf("ipup: %s\n", args_info.ipup_arg);
347 if (args_info.ipdown_arg)
348 printf("ipdown: %s\n", args_info.ipdown_arg);
349 printf("defaultroute: %d\n",
350 args_info.defaultroute_flag);
351 if (args_info.pinghost_arg)
352 printf("pinghost: %s\n",
353 args_info.pinghost_arg);
354 printf("pingrate: %d\n", args_info.pingrate_arg);
355 printf("pingsize: %d\n", args_info.pingsize_arg);
356 printf("pingcount: %d\n", args_info.pingcount_arg);
357 printf("pingquiet: %d\n", args_info.pingquiet_flag);
358 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800359 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100360 }
361 }
jjako193e8b12003-11-10 12:31:41 +0000362
Harald Weltebed35df2011-11-02 13:06:18 +0100363 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000364
Harald Weltebed35df2011-11-02 13:06:18 +0100365 /* foreground */
366 /* If fg flag not given run as a daemon */
367 /* Do not allow sgsnemu to run as deamon
368 if (!args_info.fg_flag)
369 {
370 closelog();
371 freopen("/dev/null", "w", stdout);
372 freopen("/dev/null", "w", stderr);
373 freopen("/dev/null", "r", stdin);
374 daemon(0, 0);
375 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
376 } */
jjako1a51df72004-07-20 08:30:21 +0000377
Harald Weltebed35df2011-11-02 13:06:18 +0100378 /* debug */
379 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000380
Harald Weltebed35df2011-11-02 13:06:18 +0100381 /* pidfile */
382 /* This has to be done after we have our final pid */
383 if (args_info.pidfile_arg) {
384 log_pid(args_info.pidfile_arg);
385 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200386
Harald Weltebed35df2011-11-02 13:06:18 +0100387 /* dns */
388 /* If no dns option is given use system default */
389 /* Do hostname lookup to translate hostname to IP address */
390 printf("\n");
391 if (args_info.dns_arg) {
392 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100393 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100394 "Invalid DNS address: %s!", args_info.dns_arg);
395 return -1;
396 } else {
397 memcpy(&options.dns.s_addr, host->h_addr,
398 host->h_length);
399 _res.nscount = 1;
400 _res.nsaddr_list[0].sin_addr = options.dns;
401 printf("Using DNS server: %s (%s)\n",
402 args_info.dns_arg, inet_ntoa(options.dns));
403 }
404 } else {
405 options.dns.s_addr = 0;
406 printf("Using default DNS server\n");
407 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200408
Harald Weltebed35df2011-11-02 13:06:18 +0100409 /* listen */
410 /* If no listen option is specified listen to any local port */
411 /* Do hostname lookup to translate hostname to IP address */
412 if (args_info.listen_arg) {
413 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100414 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100415 "Invalid listening address: %s!",
416 args_info.listen_arg);
417 return -1;
418 } else {
419 memcpy(&options.listen.s_addr, host->h_addr,
420 host->h_length);
421 printf("Local IP address is: %s (%s)\n",
422 args_info.listen_arg, inet_ntoa(options.listen));
423 }
424 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100425 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100426 "Listening address must be specified: %s!",
427 args_info.listen_arg);
428 return -1;
429 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200430
Harald Weltebed35df2011-11-02 13:06:18 +0100431 /* remote */
432 /* If no remote option is specified terminate */
433 /* Do hostname lookup to translate hostname to IP address */
434 if (args_info.remote_arg) {
435 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100436 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100437 "Invalid remote address: %s!",
438 args_info.remote_arg);
439 return -1;
440 } else {
441 memcpy(&options.remote.s_addr, host->h_addr,
442 host->h_length);
443 printf("Remote IP address is: %s (%s)\n",
444 args_info.remote_arg, inet_ntoa(options.remote));
445 }
446 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100447 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100448 "No remote address given!");
449 return -1;
450 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200451
Harald Weltebed35df2011-11-02 13:06:18 +0100452 /* imsi */
453 if (strlen(args_info.imsi_arg) != 15) {
454 printf("Invalid IMSI\n");
455 return -1;
456 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200457
Harald Weltebed35df2011-11-02 13:06:18 +0100458 options.imsi = 0xf000000000000000ull;
459 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
460 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
461 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
462 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
463 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
464 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
465 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
466 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
467 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
468 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
469 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
470 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
471 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
472 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
473 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200474
Harald Weltebed35df2011-11-02 13:06:18 +0100475 printf("IMSI is: %s (%#08llx)\n",
476 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200477
Harald Weltebed35df2011-11-02 13:06:18 +0100478 /* nsapi */
479 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
480 printf("Invalid NSAPI\n");
481 return -1;
482 }
483 options.nsapi = args_info.nsapi_arg;
484 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200485
Harald Weltebed35df2011-11-02 13:06:18 +0100486 /* qos */
487 options.qos.l = 4;
488 options.qos.v[3] = (args_info.qos_arg) & 0xff;
489 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
490 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
491 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
492 /* Extensions according to 3GPP TS 24.008 */
493 if (args_info.qose1_given == 1) {
494 options.qos.l = 12;
495 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
496 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
497 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
498 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
499 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
500 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
501 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
502 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
503 if (args_info.qose2_given == 1) {
504 options.qos.l = 13;
505 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
506 if (args_info.qose3_given == 1) {
507 options.qos.l = 15;
508 options.qos.v[14] =
509 (args_info.qose3_arg) & 0xff;
510 options.qos.v[13] =
511 ((args_info.qose3_arg) >> 8) & 0xff;
512 if (args_info.qose4_given == 1) {
513 options.qos.l = 17;
514 options.qos.v[16] =
515 (args_info.qose4_arg) & 0xff;
516 options.qos.v[15] =
517 ((args_info.qose4_arg) >> 8) & 0xff;
518 }
519 }
520 }
521 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200522
Harald Weltebed35df2011-11-02 13:06:18 +0100523 /* charging */
524 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200525
Harald Weltebed35df2011-11-02 13:06:18 +0100526 /* contexts */
527 if (args_info.contexts_arg > MAXCONTEXTS) {
528 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
529 return -1;
530 }
531 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200532
Harald Weltebed35df2011-11-02 13:06:18 +0100533 /* Timelimit */
534 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200535
Harald Weltebed35df2011-11-02 13:06:18 +0100536 /* gtpversion */
537 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
538 printf("Invalid GTP version\n");
539 return -1;
540 }
541 options.gtpversion = args_info.gtpversion_arg;
542 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200543
Harald Weltebed35df2011-11-02 13:06:18 +0100544 /* apn */
545 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
546 printf("Invalid APN\n");
547 return -1;
548 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100549 options.apn.l = strlen(args_info.apn_arg) + 1;
550
551 apn = (char *)options.apn.v;
552 for (tok = strtok(args_info.apn_arg, ".");
553 tok != NULL;
554 tok = strtok(NULL, ".")) {
555 size_t len = strlen(tok);
556
557 *apn++ = (char)len;
558 strncpy(apn, tok, len);
559 apn += len;
560 }
561
Harald Weltebed35df2011-11-02 13:06:18 +0100562 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200563
Harald Weltebed35df2011-11-02 13:06:18 +0100564 /* selmode */
565 options.selmode = args_info.selmode_arg;
566 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200567
Harald Weltebed35df2011-11-02 13:06:18 +0100568 /* rattype */
569 if (args_info.rattype_given == 1) {
570 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800571 options.rattype.l = 1;
572 options.rattype.v[0] = args_info.rattype_arg;
573 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100574 }
Harald Welte41af5692011-10-07 18:42:34 +0200575
Harald Weltebed35df2011-11-02 13:06:18 +0100576 /* userloc */
577 if (args_info.userloc_given == 1) {
578 printf("Using User Location Information: %s\n",
579 args_info.userloc_arg);
580 tmp = args_info.userloc_arg;
581 n = 0;
582 pch = strtok(tmp, ".");
583 while (pch != NULL) {
584 userloc_el[n] = pch;
585 pch = strtok(NULL, ".");
586 n++;
587 }
Harald Welte41af5692011-10-07 18:42:34 +0200588
Harald Weltebed35df2011-11-02 13:06:18 +0100589 options.userloc_given = 1;
590 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200591
Harald Weltebed35df2011-11-02 13:06:18 +0100592 /* 3GPP Geographic Location Type t0 / t1 / t2 */
593 type = userloc_el[0];
594 printf("->type : %c\n", type[0]);
595 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
596 printf("Invalid type \n");
597 return -1;
598 }
599 /* options.userloc.v[0] = 0x00 */
600 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200601
Harald Weltebed35df2011-11-02 13:06:18 +0100602 /* MCC */
603 mcc = userloc_el[1];
604 printf("->mcc : %s\n", mcc);
605 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200606 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100607 return -1;
608 }
Harald Welte41af5692011-10-07 18:42:34 +0200609
Harald Weltebed35df2011-11-02 13:06:18 +0100610 /* MNC */
611 mnc = userloc_el[2];
612 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200613
Harald Weltebed35df2011-11-02 13:06:18 +0100614 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
615 /* options.userloc.v[1] = 0x52 */
616 a = (uint8_t) (mcc[0] - 48);
617 b = (uint8_t) (mcc[1] - 48);
618 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200619
Harald Weltebed35df2011-11-02 13:06:18 +0100620 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
621 /* options.userloc.v[2] = 0xf0 */
622 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200623
Harald Weltebed35df2011-11-02 13:06:18 +0100624 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200625 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100626 return -1;
627 }
628 if (strlen(mnc) == 2) {
629 b = 15;
630 }
631 if (strlen(mnc) == 3) {
632 b = (uint8_t) (mnc[2] - 48);
633 }
634 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200635
Harald Weltebed35df2011-11-02 13:06:18 +0100636 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
637 /* options.userloc.v[3] = 0x99 */
638 a = (uint8_t) (mnc[0] - 48);
639 b = (uint8_t) (mnc[1] - 48);
640 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200641
Harald Weltebed35df2011-11-02 13:06:18 +0100642 /* LAC */
643 lac = userloc_el[3];
644 /*options.userloc.v[4] = 0x12 ; */
645 /*options.userloc.v[5] = 0x10 ; */
646 printf("->LAC: %s\n", lac);
647 lac_d = atoi(lac);
648 if (lac_d > 65535 || lac_d < 1) {
649 printf("Invalid LAC\n");
650 return -1;
651 }
652 i = lac_d >> 8;
653 options.userloc.v[4] = i; /* octet 8 - LAC */
654 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200655
Harald Weltebed35df2011-11-02 13:06:18 +0100656 /* CI/SAC/RAC */
657 rest = userloc_el[4];
658 printf("->CI/SAC/RAC : %s\n", rest);
659 lac_d = atoi(rest);
660 if (lac_d > 65535 || lac_d < 1) {
661 printf("Invalid CI/SAC/RAC\n");
662 return -1;
663 }
664 /*options.userloc.v[6] = 0x04 ; */
665 /*options.userloc.v[7] = 0xb7 ; */
666 i = lac_d >> 8;
667 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
668 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
669 }
jjakoa7cd2492003-04-11 09:40:12 +0000670
Harald Weltebed35df2011-11-02 13:06:18 +0100671 /* RAI */
672 if (args_info.rai_given == 1) {
673 printf("Using RAI: %s\n", args_info.rai_arg);
674 tmp = args_info.rai_arg;
675 n = 0;
676 pch = strtok(tmp, ".");
677 while (pch != NULL) {
678 rai_el[n] = pch;
679 pch = strtok(NULL, ".");
680 n++;
681 }
jjakoa7cd2492003-04-11 09:40:12 +0000682
Harald Weltebed35df2011-11-02 13:06:18 +0100683 options.rai_given = 1;
684 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000685
Harald Weltebed35df2011-11-02 13:06:18 +0100686 /* MCC */
687 mcc = rai_el[0];
688 printf("->mcc : %s\n", mcc);
689 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200690 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100691 return -1;
692 }
693
694 /* MNC */
695 mnc = rai_el[1];
696 printf("->mnc : %s\n", mnc);
697
698 a = (uint8_t) (mcc[0] - 48);
699 b = (uint8_t) (mcc[1] - 48);
700 options.rai.v[0] = 16 * b + a;
701
702 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
703 a = (uint8_t) (mcc[2] - 48);
704
705 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200706 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100707 return -1;
708 }
709 if (strlen(mnc) == 2) {
710 b = 15;
711 }
712 if (strlen(mnc) == 3) {
713 b = (uint8_t) (mnc[2] - 48);
714 }
715 options.rai.v[1] = 16 * b + a;
716
717 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
718 a = (uint8_t) (mnc[0] - 48);
719 b = (uint8_t) (mnc[1] - 48);
720 options.rai.v[2] = 16 * b + a;
721
722 /* LAC */
723 lac = rai_el[2];
724 printf("->LAC: %s\n", lac);
725 lac_d = atoi(lac);
726 if (lac_d > 65535 || lac_d < 1) {
727 printf("Invalid LAC\n");
728 return -1;
729 }
730 i = lac_d >> 8;
731 options.rai.v[3] = i; /* octet 5 - LAC */
732 options.rai.v[4] = lac_d; /* octet 6 - LAC */
733
734 /* RAC */
735 rest = rai_el[3];
736 printf("->RAC : %s\n", rest);
737 lac_d = atoi(rest);
738 if (lac_d > 255 || lac_d < 1) {
739 printf("Invalid RAC\n");
740 return -1;
741 }
742 options.rai.v[5] = lac_d; /* octet 7 - RAC */
743 }
744
745 /* mstz */
746 if (args_info.mstz_given == 1) {
747 options.mstz_given = 1;
748 options.mstz.l = 2;
749
750 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
751 tmp = args_info.mstz_arg;
752 n = 0;
753 pch = strtok(tmp, ".");
754 while (pch != NULL) {
755 mstz_el[n] = pch;
756 pch = strtok(NULL, ".");
757 n++;
758 }
759
760 /* sign */
761 sign = atoi(mstz_el[0]);
762 printf("->Sign (0=+ / 1=-): %d\n", sign);
763 if (sign != 0 && sign != 1) {
764 printf("Invalid Sign \n");
765 return -1;
766 }
767 /* nbquarters */
768 nbquarters = atoi(mstz_el[1]);
769 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
770 if (nbquarters < 0 || nbquarters > 79) {
771 printf("Invalid Number of Quarters \n");
772 return -1;
773 }
774 /* DST */
775 DST = atoi(mstz_el[2]);
776 printf("->Daylight Saving Time Adjustment : %d\n", DST);
777 if (DST < 0 || DST > 3) {
778 printf("Invalid DST Adjustment \n");
779 return -1;
780 }
781 /* 12345678
782 bits 123 = unit of # of quarters of an hour
783 bits 678 = # of quarters of an hour / 10
784 bit 5 = sign
785 */
786 i = nbquarters % 10;
787 i = i << 4;
788 i = i + nbquarters / 10 + 8 * sign;
789 /* options.mstz.v[0] = 0x69 ; */
790 /* options.mstz.v[1] = 0x01 ; */
791 options.mstz.v[0] = i;
792 options.mstz.v[1] = DST;
793 n = (i & 0x08) ? '-' : '+';
794 printf
795 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
796 n, nbquarters / 4, nbquarters % 4 * 15);
797 }
798
799 /* imeisv */
800 if (args_info.imeisv_given == 1) {
801 options.imeisv_given = 1;
802 if (strlen(args_info.imeisv_arg) != 16) {
803 printf("Invalid IMEI(SV)\n");
804 return -1;
805 }
806 options.imeisv.l = 8;
807 for (n = 0; n < 8; n++) {
808 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
809 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
810 options.imeisv.v[n] = 16 * b + a;
811 }
812 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
813 }
814
815 /* msisdn */
816 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
817 printf("Invalid MSISDN\n");
818 return -1;
819 }
820 options.msisdn.l = 1;
821 options.msisdn.v[0] = 0x91; /* International format */
822 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
823 if ((n % 2) == 0) {
824 options.msisdn.v[((int)n / 2) + 1] =
825 args_info.msisdn_arg[n] - 48 + 0xf0;
826 options.msisdn.l += 1;
827 } else {
828 options.msisdn.v[((int)n / 2) + 1] =
829 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
830 (args_info.msisdn_arg[n] - 48) * 16;
831 }
832 }
833 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
834
835 /* UID and PWD */
836 /* Might need to also insert stuff like DNS etc. */
837 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
838 (sizeof(options.pco.v) - 1)) {
839 printf("invalid UID and PWD\n");
840 return -1;
841 }
842 options.pco.l =
843 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
844 options.pco.v[0] = 0x80; /* PPP */
845 options.pco.v[1] = 0xc0; /* PAP */
846 options.pco.v[2] = 0x23;
847 options.pco.v[3] =
848 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
849 options.pco.v[4] = 0x01; /* Authenticate request */
850 options.pco.v[5] = 0x01;
851 options.pco.v[6] = 0x00; /* MSB of length */
852 options.pco.v[7] =
853 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
854 options.pco.v[8] = strlen(args_info.uid_arg);
855 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
856 options.pco.v[9 + strlen(args_info.uid_arg)] =
857 strlen(args_info.pwd_arg);
858 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
859 args_info.pwd_arg, strlen(args_info.pwd_arg));
860
861 /* createif */
862 options.createif = args_info.createif_flag;
863
864 /* net */
865 /* Store net as in_addr net and mask */
866 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200867 struct in46_addr in46;
Harald Weltebed35df2011-11-02 13:06:18 +0100868 if (ippool_aton
Harald Welted12eab92017-08-02 19:49:47 +0200869 (&in46, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100870 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100871 "Invalid network address: %s!",
872 args_info.net_arg);
873 exit(1);
874 }
Harald Welted12eab92017-08-02 19:49:47 +0200875 options.net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100876 options.netaddr.s_addr = options.net.s_addr;
877 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000878
Harald Weltebed35df2011-11-02 13:06:18 +0100879 } else {
880 options.net.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200881 options.prefixlen = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100882 options.netaddr.s_addr = 0;
883 options.destaddr.s_addr = 0;
884 }
jjako193e8b12003-11-10 12:31:41 +0000885
Harald Weltebed35df2011-11-02 13:06:18 +0100886 /* ipup */
887 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000888
Harald Weltebed35df2011-11-02 13:06:18 +0100889 /* ipdown */
890 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000891
Harald Weltebed35df2011-11-02 13:06:18 +0100892 /* statedir */
893 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000894
Harald Weltebed35df2011-11-02 13:06:18 +0100895 /* defaultroute */
896 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000897
Harald Weltebed35df2011-11-02 13:06:18 +0100898 /* pinghost */
899 /* Store ping host as in_addr */
900 if (args_info.pinghost_arg) {
901 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100902 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100903 "Invalid ping host: %s!",
904 args_info.pinghost_arg);
905 return -1;
906 } else {
907 memcpy(&options.pinghost.s_addr, host->h_addr,
908 host->h_length);
909 printf("Using ping host: %s (%s)\n",
910 args_info.pinghost_arg,
911 inet_ntoa(options.pinghost));
912 }
913 }
jjakoa7cd2492003-04-11 09:40:12 +0000914
Harald Weltebed35df2011-11-02 13:06:18 +0100915 /* Other ping parameters */
916 options.pingrate = args_info.pingrate_arg;
917 options.pingsize = args_info.pingsize_arg;
918 options.pingcount = args_info.pingcount_arg;
919 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000920
Harald Weltebed35df2011-11-02 13:06:18 +0100921 /* norecovery */
922 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000923
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800924 if (args_info.no_tx_gpdu_seq_flag)
925 options.tx_gpdu_seq = 0;
926 else
927 options.tx_gpdu_seq = 1;
928
Harald Weltebed35df2011-11-02 13:06:18 +0100929 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000930
931}
932
Harald Weltebed35df2011-11-02 13:06:18 +0100933int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
934{
935 unsigned int i;
936 printf("The packet looks like this:\n");
937 for (i = 0; i < len; i++) {
938 printf("%02x ", (unsigned char)*(char *)(pack + i));
939 if (!((i + 1) % 16))
940 printf("\n");
941 };
942 printf("\n");
943 return 0;
jjako52c24142002-12-16 13:33:51 +0000944}
945
Harald Weltebed35df2011-11-02 13:06:18 +0100946char *print_ipprot(int t)
947{
948 switch (t) {
949 case 1:
950 return "ICMP";
951 case 6:
952 return "TCP";
953 case 17:
954 return "UDP";
955 default:
956 return "Unknown";
957 };
jjako5da68452003-01-28 16:08:47 +0000958}
959
Harald Weltebed35df2011-11-02 13:06:18 +0100960char *print_icmptype(int t)
961{
962 static char *ttab[] = {
963 "Echo Reply",
964 "ICMP 1",
965 "ICMP 2",
966 "Dest Unreachable",
967 "Source Quench",
968 "Redirect",
969 "ICMP 6",
970 "ICMP 7",
971 "Echo",
972 "ICMP 9",
973 "ICMP 10",
974 "Time Exceeded",
975 "Parameter Problem",
976 "Timestamp",
977 "Timestamp Reply",
978 "Info Request",
979 "Info Reply"
980 };
981 if (t < 0 || t > 16)
982 return ("OUT-OF-RANGE");
983 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +0000984}
985
Harald Weltebed35df2011-11-02 13:06:18 +0100986int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
987{
988 unsigned int n;
989 uint64_t i64 = 0;
990 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
991 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +0000992
Harald Weltebed35df2011-11-02 13:06:18 +0100993 /* Convert to uint64_t from ul16_t format (most significant digit first) */
994 /* ul16_t format always starts with 0x91 to indicate international format */
995 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
996 for (n = 0; n < src->l; n++) {
997 if ((src->v[n] & 0x0f) != 0x0f) {
998 i64 *= 10;
999 i64 += src->v[n] & 0x0f;
1000 }
1001 if ((src->v[n] & 0xf0) != 0xf0) {
1002 i64 *= 10;
1003 i64 += (src->v[n] & 0xf0) >> 4;
1004 }
1005 }
jjako193e8b12003-11-10 12:31:41 +00001006
Harald Weltebed35df2011-11-02 13:06:18 +01001007 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001008
Harald Weltebed35df2011-11-02 13:06:18 +01001009 /* Generate array with least significant digit in first octet */
1010 while (i64) {
1011 msa[msalen++] = i64 % 10;
1012 i64 = i64 / 10;
1013 }
jjako193e8b12003-11-10 12:31:41 +00001014
Harald Weltebed35df2011-11-02 13:06:18 +01001015 /* Convert back to ul16_t format */
1016 for (n = 0; n < msalen; n++) {
1017 if ((n % 2) == 0) {
1018 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1019 dst->l += 1;
1020 } else {
1021 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1022 msa[msalen - n - 1] * 16;
1023 }
1024 }
jjako193e8b12003-11-10 12:31:41 +00001025
Harald Weltebed35df2011-11-02 13:06:18 +01001026 return 0;
jjako193e8b12003-11-10 12:31:41 +00001027
1028}
1029
Harald Weltebed35df2011-11-02 13:06:18 +01001030int imsi_add(uint64_t src, uint64_t * dst, int add)
1031{
1032 /* TODO: big endian / small endian ??? */
1033 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001034
Harald Weltebed35df2011-11-02 13:06:18 +01001035 /* Convert from uint64_t bcd to uint64_t integer format */
1036 /* The resulting integer format is multiplied by 10 */
1037 while (src) {
1038 if ((src & 0x0f) != 0x0f) {
1039 i64 *= 10;
1040 i64 += (src & 0x0f);
1041 }
1042 if ((src & 0xf0) != 0xf0) {
1043 i64 *= 10;
1044 i64 += (src & 0xf0) >> 4;
1045 }
1046 src = src >> 8;
1047 }
jjako193e8b12003-11-10 12:31:41 +00001048
Harald Weltebed35df2011-11-02 13:06:18 +01001049 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001050
Harald Weltebed35df2011-11-02 13:06:18 +01001051 *dst = 0;
1052 while (i64) {
1053 *dst = *dst << 4;
1054 *dst += (i64 % 10);
1055 i64 = i64 / 10;
1056 }
jjako193e8b12003-11-10 12:31:41 +00001057
Harald Weltebed35df2011-11-02 13:06:18 +01001058 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001059
Harald Weltebed35df2011-11-02 13:06:18 +01001060 return 0;
jjako193e8b12003-11-10 12:31:41 +00001061
1062}
1063
jjakoafb2a972003-01-29 21:04:13 +00001064/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001065int ping_timeout(struct timeval *tp)
1066{
1067 struct timezone tz;
1068 struct timeval tv;
1069 int diff;
1070 if ((options.pinghost.s_addr) && (2 == state) &&
1071 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1072 gettimeofday(&tv, &tz);
1073 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1074 tp->tv_sec = 0;
1075 if (diff > 0)
1076 tp->tv_usec = diff;
1077 else {
1078 /* For some reason we get packet loss if set to zero */
1079 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1080 tp->tv_usec = 0;
1081 }
1082 }
1083 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001084}
1085
jjako5da68452003-01-28 16:08:47 +00001086/* Print out statistics when at the end of ping sequence */
1087int ping_finish()
1088{
Harald Weltebed35df2011-11-02 13:06:18 +01001089 struct timezone tz;
1090 struct timeval tv;
1091 int elapsed;
1092 gettimeofday(&tv, &tz);
1093 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1094 printf("\n");
1095 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1096 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1097 elapsed / 1000000.0);
1098 printf("%d packets received, ", nreceived);
1099 if (ntransmitted) {
1100 if (nreceived > ntransmitted)
1101 printf("-- somebody's printing up packets!");
1102 else
1103 printf("%d%% packet loss",
1104 (int)(((ntransmitted - nreceived) * 100) /
1105 ntransmitted));
1106 }
1107 printf("\n");
1108 if (options.debug)
1109 printf("%d packets received in total\n", ntreceived);
1110 if (nreceived && tsum)
1111 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1112 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1113 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001114
Harald Weltebed35df2011-11-02 13:06:18 +01001115 ntransmitted = 0;
1116 return 0;
jjako5da68452003-01-28 16:08:47 +00001117}
1118
1119/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001120int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1121{
1122 struct timezone tz;
1123 struct timeval tv;
1124 struct timeval *tp;
1125 struct ip_ping *pingpack = pack;
1126 struct in_addr src;
1127 int triptime;
jjako5da68452003-01-28 16:08:47 +00001128
Harald Weltebed35df2011-11-02 13:06:18 +01001129 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001130
Harald Weltebed35df2011-11-02 13:06:18 +01001131 gettimeofday(&tv, &tz);
1132 if (options.debug)
1133 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001134
Harald Weltebed35df2011-11-02 13:06:18 +01001135 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1136 printf("packet too short (%d bytes) from %s\n", len,
1137 inet_ntoa(src));
1138 return 0;
1139 }
jjako5da68452003-01-28 16:08:47 +00001140
Harald Weltebed35df2011-11-02 13:06:18 +01001141 ntreceived++;
1142 if (pingpack->protocol != 1) {
1143 if (!options.pingquiet)
1144 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1145 len, inet_ntoa(src), pingpack->protocol,
1146 print_ipprot(pingpack->protocol));
1147 return 0;
1148 }
jjako5da68452003-01-28 16:08:47 +00001149
Harald Weltebed35df2011-11-02 13:06:18 +01001150 if (pingpack->type != 0) {
1151 if (!options.pingquiet)
1152 printf
1153 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1154 len, inet_ntoa(src), pingpack->type,
1155 print_icmptype(pingpack->type), pingpack->code);
1156 return 0;
1157 }
jjako5da68452003-01-28 16:08:47 +00001158
Harald Weltebed35df2011-11-02 13:06:18 +01001159 nreceived++;
1160 if (!options.pingquiet)
1161 printf("%d bytes from %s: icmp_seq=%d", len,
1162 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001163
Harald Weltebed35df2011-11-02 13:06:18 +01001164 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1165 gettimeofday(&tv, &tz);
1166 tp = (struct timeval *)pingpack->data;
1167 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1168 tv.tv_sec--;
1169 tv.tv_usec += 1000000;
1170 }
1171 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001172
Harald Weltebed35df2011-11-02 13:06:18 +01001173 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1174 tsum += triptime;
1175 if (triptime < tmin)
1176 tmin = triptime;
1177 if (triptime > tmax)
1178 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001179
Harald Weltebed35df2011-11-02 13:06:18 +01001180 if (!options.pingquiet)
1181 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001182
Harald Weltebed35df2011-11-02 13:06:18 +01001183 } else if (!options.pingquiet)
1184 printf("\n");
1185 return 0;
jjako5da68452003-01-28 16:08:47 +00001186}
1187
1188/* Create a new ping packet and send it off to peer. */
1189int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001190 struct in_addr *dst, int seq, unsigned int datasize)
1191{
jjako5da68452003-01-28 16:08:47 +00001192
Harald Weltebed35df2011-11-02 13:06:18 +01001193 struct ip_ping pack;
1194 uint16_t *p = (uint16_t *) & pack;
1195 uint8_t *p8 = (uint8_t *) & pack;
1196 struct in_addr src;
1197 unsigned int n;
1198 long int sum = 0;
1199 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001200
Harald Weltebed35df2011-11-02 13:06:18 +01001201 struct timezone tz;
1202 struct timeval *tp =
1203 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001204
Harald Weltebed35df2011-11-02 13:06:18 +01001205 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001206 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001207 "Ping size to large: %d!", datasize);
1208 return -1;
1209 }
jjako5da68452003-01-28 16:08:47 +00001210
Harald Weltebed35df2011-11-02 13:06:18 +01001211 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001212
Harald Weltebed35df2011-11-02 13:06:18 +01001213 pack.ipver = 0x45;
1214 pack.tos = 0x00;
1215 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1216 pack.fragid = 0x0000;
1217 pack.offset = 0x0040;
1218 pack.ttl = 0x40;
1219 pack.protocol = 0x01;
1220 pack.ipcheck = 0x0000;
1221 pack.src = src.s_addr;
1222 pack.dst = dst->s_addr;
1223 pack.type = 0x08;
1224 pack.code = 0x00;
1225 pack.checksum = 0x0000;
1226 pack.ident = 0x0000;
1227 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001228
Harald Weltebed35df2011-11-02 13:06:18 +01001229 /* Generate ICMP payload */
1230 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1231 for (n = 0; n < (datasize); n++)
1232 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001233
Harald Weltebed35df2011-11-02 13:06:18 +01001234 if (datasize >= sizeof(struct timeval))
1235 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001236
Harald Weltebed35df2011-11-02 13:06:18 +01001237 /* Calculate IP header checksum */
1238 p = (uint16_t *) & pack;
1239 count = CREATEPING_IP;
1240 sum = 0;
1241 while (count > 1) {
1242 sum += *p++;
1243 count -= 2;
1244 }
1245 while (sum >> 16)
1246 sum = (sum & 0xffff) + (sum >> 16);
1247 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001248
Harald Weltebed35df2011-11-02 13:06:18 +01001249 /* Calculate ICMP checksum */
1250 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1251 sum = 0;
1252 p = (uint16_t *) & pack;
1253 p += CREATEPING_IP / 2;
1254 while (count > 1) {
1255 sum += *p++;
1256 count -= 2;
1257 }
1258 if (count > 0)
1259 sum += *(unsigned char *)p;
1260 while (sum >> 16)
1261 sum = (sum & 0xffff) + (sum >> 16);
1262 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001263
Harald Weltebed35df2011-11-02 13:06:18 +01001264 ntransmitted++;
1265 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001266}
1267
Harald Weltebed35df2011-11-02 13:06:18 +01001268int delete_context(struct pdp_t *pdp)
1269{
1270
1271 if (tun && options.ipdown)
1272 tun_runscript(tun, options.ipdown);
1273
1274 ipdel((struct iphash_t *)pdp->peer);
1275 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1276
1277 if (1 == options.contexts)
1278 state = 5; /* Disconnected */
1279
1280 return 0;
1281}
jjakoa7cd2492003-04-11 09:40:12 +00001282
1283/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001284int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1285{
1286 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001287 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001288 struct iphdr *iph = (struct iphdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001289
Harald Welted12eab92017-08-02 19:49:47 +02001290 src.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +02001291 src.v4.s_addr = iph->saddr;
jjakoa7cd2492003-04-11 09:40:12 +00001292
Harald Weltebed35df2011-11-02 13:06:18 +01001293 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001294 printf("Dropping packet from invalid source address: %s\n",
Harald Welted12eab92017-08-02 19:49:47 +02001295 inet_ntoa(src.v4));
Harald Weltebed35df2011-11-02 13:06:18 +01001296 return 0;
1297 }
1298
1299 if (ipm->pdp) /* Check if a peer protocol is defined */
1300 gtp_data_req(gsn, ipm->pdp, pack, len);
1301 return 0;
jjako52c24142002-12-16 13:33:51 +00001302}
1303
Harald Weltebed35df2011-11-02 13:06:18 +01001304int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1305{
Harald Welted12eab92017-08-02 19:49:47 +02001306 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001307
Harald Weltebed35df2011-11-02 13:06:18 +01001308 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001309
Harald Weltebed35df2011-11-02 13:06:18 +01001310 if (cause < 0) {
1311 printf("Create PDP Context Request timed out\n");
1312 if (iph->pdp->version == 1) {
1313 printf("Retrying with version 0\n");
1314 iph->pdp->version = 0;
1315 gtp_create_context_req(gsn, iph->pdp, iph);
1316 return 0;
1317 } else {
1318 state = 0;
1319 pdp_freepdp(iph->pdp);
1320 iph->pdp = NULL;
1321 return EOF;
1322 }
1323 }
jjako2c381332003-10-21 19:09:53 +00001324
Harald Weltebed35df2011-11-02 13:06:18 +01001325 if (cause != 128) {
1326 printf
1327 ("Received create PDP context response. Cause value: %d\n",
1328 cause);
1329 state = 0;
1330 pdp_freepdp(iph->pdp);
1331 iph->pdp = NULL;
1332 return EOF; /* Not what we expected */
1333 }
jjako52c24142002-12-16 13:33:51 +00001334
Harald Weltea0d281d2017-08-02 21:48:16 +02001335 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001336 printf
1337 ("Received create PDP context response. Cause value: %d\n",
1338 cause);
1339 pdp_freepdp(iph->pdp);
1340 iph->pdp = NULL;
1341 state = 0;
1342 return EOF; /* Not a valid IP address */
1343 }
jjakoa7cd2492003-04-11 09:40:12 +00001344
Harald Weltebed35df2011-11-02 13:06:18 +01001345 printf("Received create PDP context response. IP address: %s\n",
Harald Welted12eab92017-08-02 19:49:47 +02001346 inet_ntoa(addr.v4));
jjakoa7cd2492003-04-11 09:40:12 +00001347
Harald Weltebed35df2011-11-02 13:06:18 +01001348 if ((options.createif) && (!options.net.s_addr)) {
1349 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +00001350#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +01001351 inet_aton("255.255.255.255", &m);
jjako1d3db972004-01-16 09:56:56 +00001352#else
Harald Weltebed35df2011-11-02 13:06:18 +01001353 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +00001354#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001355 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001356 tun_addaddr(tun, &addr.v4, &addr.v4, &m);
Harald Weltebed35df2011-11-02 13:06:18 +01001357 if (options.defaultroute) {
1358 struct in_addr rm;
1359 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001360 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001361 }
1362 if (options.ipup)
1363 tun_runscript(tun, options.ipup);
1364 }
jjako52c24142002-12-16 13:33:51 +00001365
Harald Weltebed35df2011-11-02 13:06:18 +01001366 ipset((struct iphash_t *)pdp->peer, &addr);
1367
1368 state = 2; /* Connected */
1369
1370 return 0;
jjako52c24142002-12-16 13:33:51 +00001371}
1372
Harald Weltebed35df2011-11-02 13:06:18 +01001373int delete_pdp_conf(struct pdp_t *pdp, int cause)
1374{
1375 printf("Received delete PDP context response. Cause value: %d\n",
1376 cause);
1377 return 0;
jjako52c24142002-12-16 13:33:51 +00001378}
1379
Harald Weltebed35df2011-11-02 13:06:18 +01001380int echo_conf(int recovery)
1381{
jjako91aaf222003-10-22 10:09:32 +00001382
Harald Weltebed35df2011-11-02 13:06:18 +01001383 if (recovery < 0) {
1384 printf("Echo Request timed out\n");
1385 if (echoversion == 1) {
1386 printf("Retrying with version 0\n");
1387 echoversion = 0;
1388 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1389 return 0;
1390 } else {
1391 state = 0;
1392 return EOF;
1393 }
1394 } else {
1395 printf("Received echo response\n");
1396 if (!options.contexts)
1397 state = 5;
1398 }
1399 return 0;
jjako52c24142002-12-16 13:33:51 +00001400}
1401
Harald Weltebed35df2011-11-02 13:06:18 +01001402int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1403{
1404 /* if (cause < 0) return 0; Some error occurred. We don't care */
1405 switch (type) {
1406 case GTP_ECHO_REQ:
1407 return echo_conf(cause);
1408 case GTP_CREATE_PDP_REQ:
1409 return create_pdp_conf(pdp, cbp, cause);
1410 case GTP_DELETE_PDP_REQ:
1411 if (cause != 128)
1412 return 0; /* Request not accepted. We don't care */
1413 return delete_pdp_conf(pdp, cause);
1414 default:
1415 return 0;
1416 }
jjako52c24142002-12-16 13:33:51 +00001417}
1418
Harald Weltebed35df2011-11-02 13:06:18 +01001419int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1420{
1421 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1422 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001423}
1424
1425int main(int argc, char **argv)
1426{
Harald Weltebed35df2011-11-02 13:06:18 +01001427 fd_set fds; /* For select() */
1428 struct timeval idleTime; /* How long to select() */
1429 struct pdp_t *pdp;
1430 int n;
1431 int starttime = time(NULL); /* Time program was started */
1432 int stoptime = 0; /* Time to exit */
1433 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001434 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001435
Harald Weltebed35df2011-11-02 13:06:18 +01001436 struct timezone tz; /* Used for calculating ping times */
1437 struct timeval tv;
1438 int diff;
jjako52c24142002-12-16 13:33:51 +00001439
bjovana8f71eb2017-02-24 17:39:20 +01001440 signal(SIGTERM, signal_handler);
1441 signal(SIGHUP, signal_handler);
1442 signal(SIGINT, signal_handler);
1443
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001444 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001445
Harald Weltebed35df2011-11-02 13:06:18 +01001446 /* Process options given in configuration file and command line */
1447 if (process_options(argc, argv))
1448 exit(1);
jjako52c24142002-12-16 13:33:51 +00001449
Harald Weltebed35df2011-11-02 13:06:18 +01001450 printf("\nInitialising GTP library\n");
1451 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001452 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001453 exit(1);
1454 }
1455 if (gsn->fd0 > maxfd)
1456 maxfd = gsn->fd0;
1457 if (gsn->fd1c > maxfd)
1458 maxfd = gsn->fd1c;
1459 if (gsn->fd1u > maxfd)
1460 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001461
Harald Weltebed35df2011-11-02 13:06:18 +01001462 gtp_set_cb_delete_context(gsn, delete_context);
1463 gtp_set_cb_conf(gsn, conf);
1464 if (options.createif)
1465 gtp_set_cb_data_ind(gsn, encaps_tun);
1466 else
1467 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001468
Harald Weltebed35df2011-11-02 13:06:18 +01001469 if (options.createif) {
1470 printf("Setting up interface\n");
1471 /* Create a tunnel interface */
Harald Weltedda21ed2017-08-12 15:07:02 +02001472 if (tun_new((struct tun_t **)&tun, NULL)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001473 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001474 "Failed to create tun");
1475 exit(1);
1476 }
1477 tun_set_cb_ind(tun, cb_tun_ind);
1478 if (tun->fd > maxfd)
1479 maxfd = tun->fd;
1480 }
jjakoa7cd2492003-04-11 09:40:12 +00001481
Harald Weltebed35df2011-11-02 13:06:18 +01001482 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001483 struct in_addr mask;
1484 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001485 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001486 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001487 if (options.defaultroute) {
1488 struct in_addr rm;
1489 rm.s_addr = 0;
1490 tun_addroute(tun, &rm, &options.destaddr, &rm);
1491 }
1492 if (options.ipup)
1493 tun_runscript(tun, options.ipup);
1494 }
jjakoa7cd2492003-04-11 09:40:12 +00001495
Harald Weltebed35df2011-11-02 13:06:18 +01001496 /* Initialise hash tables */
1497 memset(&iphash, 0, sizeof(iphash));
1498 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001499
Harald Weltebed35df2011-11-02 13:06:18 +01001500 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001501
Harald Weltebed35df2011-11-02 13:06:18 +01001502 /* See if anybody is there */
1503 printf("Sending off echo request\n");
1504 echoversion = options.gtpversion;
1505 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001506
Harald Weltebed35df2011-11-02 13:06:18 +01001507 for (n = 0; n < options.contexts; n++) {
1508 uint64_t myimsi;
1509 printf("Setting up PDP context #%d\n", n);
1510 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001511
Harald Weltebed35df2011-11-02 13:06:18 +01001512 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001513
Harald Weltebed35df2011-11-02 13:06:18 +01001514 /* Allocated here. */
1515 /* If create context failes we have to deallocate ourselves. */
1516 /* Otherwise it is deallocated by gtplib */
1517 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001518
Harald Weltebed35df2011-11-02 13:06:18 +01001519 pdp->peer = &iparr[n];
1520 pdp->ipif = tun; /* TODO */
1521 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001522
Harald Weltebed35df2011-11-02 13:06:18 +01001523 if (options.gtpversion == 0) {
1524 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001525 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001526 "QoS length too big");
1527 exit(1);
1528 } else {
1529 memcpy(pdp->qos_req0, options.qos.v,
1530 options.qos.l);
1531 }
1532 }
jjakoa7cd2492003-04-11 09:40:12 +00001533
Harald Weltebed35df2011-11-02 13:06:18 +01001534 pdp->qos_req.l = options.qos.l;
1535 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001536
Harald Weltebed35df2011-11-02 13:06:18 +01001537 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001538
Harald Weltebed35df2011-11-02 13:06:18 +01001539 pdp->rattype.l = options.rattype.l;
1540 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1541 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001542
Harald Weltebed35df2011-11-02 13:06:18 +01001543 pdp->userloc.l = options.userloc.l;
1544 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1545 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001546
Harald Weltebed35df2011-11-02 13:06:18 +01001547 pdp->rai.l = options.rai.l;
1548 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1549 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001550
Harald Weltebed35df2011-11-02 13:06:18 +01001551 pdp->mstz.l = options.mstz.l;
1552 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1553 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001554
Harald Weltebed35df2011-11-02 13:06:18 +01001555 pdp->imeisv.l = options.imeisv.l;
1556 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1557 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001558
Harald Weltebed35df2011-11-02 13:06:18 +01001559 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001560
Harald Weltebed35df2011-11-02 13:06:18 +01001561 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001562 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001563 "APN length too big");
1564 exit(1);
1565 } else {
1566 pdp->apn_use.l = options.apn.l;
1567 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1568 }
jjako193e8b12003-11-10 12:31:41 +00001569
Harald Weltebed35df2011-11-02 13:06:18 +01001570 pdp->gsnlc.l = sizeof(options.listen);
1571 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1572 pdp->gsnlu.l = sizeof(options.listen);
1573 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001574
Harald Weltebed35df2011-11-02 13:06:18 +01001575 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001576 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001577 "MSISDN length too big");
1578 exit(1);
1579 } else {
1580 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1581 }
jjakob62c3dd2004-05-27 18:51:55 +00001582
Harald Weltebed35df2011-11-02 13:06:18 +01001583 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
jjako52c24142002-12-16 13:33:51 +00001584
Harald Weltebed35df2011-11-02 13:06:18 +01001585 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001586 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001587 "PCO length too big");
1588 exit(1);
1589 } else {
1590 pdp->pco_req.l = options.pco.l;
1591 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1592 }
jjako52c24142002-12-16 13:33:51 +00001593
Harald Weltebed35df2011-11-02 13:06:18 +01001594 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001595
Harald Weltebed35df2011-11-02 13:06:18 +01001596 pdp->hisaddr0 = options.remote;
1597 pdp->hisaddr1 = options.remote;
1598
1599 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1600 512 = Flat rate, 256 = Hot billing */
1601
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001602 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1603
Harald Weltebed35df2011-11-02 13:06:18 +01001604 /* Create context */
1605 /* We send this of once. Retransmissions are handled by gtplib */
1606 gtp_create_context_req(gsn, pdp, &iparr[n]);
1607 }
1608
1609 state = 1; /* Enter wait_connection state */
1610
1611 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001612
jjako52c24142002-12-16 13:33:51 +00001613 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001614 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001615 /******************************************************************/
1616
Harald Weltebed35df2011-11-02 13:06:18 +01001617 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001618
Harald Weltebed35df2011-11-02 13:06:18 +01001619 /* Take down client after timeout after disconnect */
1620 if ((4 == state) && ((stoptime) <= time(NULL))) {
1621 state = 5;
1622 }
jjako7b8fad42003-07-07 14:37:42 +00001623
Harald Weltebed35df2011-11-02 13:06:18 +01001624 /* Take down client after timelimit timeout */
1625 if ((2 == state) && (options.timelimit) &&
1626 ((starttime + options.timelimit) <= time(NULL))) {
1627 state = 3;
1628 }
jjako7b8fad42003-07-07 14:37:42 +00001629
Harald Weltebed35df2011-11-02 13:06:18 +01001630 /* Take down client after ping timeout */
1631 if ((2 == state) && (pingtimeout)
1632 && (pingtimeout <= time(NULL))) {
1633 state = 3;
1634 }
jjako7b8fad42003-07-07 14:37:42 +00001635
Harald Weltebed35df2011-11-02 13:06:18 +01001636 /* Set pingtimeout for later disconnection */
1637 if (options.pingcount && ntransmitted >= options.pingcount) {
1638 pingtimeout = time(NULL) + 5; /* Extra seconds */
1639 }
jjako7b8fad42003-07-07 14:37:42 +00001640
Harald Weltebed35df2011-11-02 13:06:18 +01001641 /* Print statistics if no more ping packets are missing */
1642 if (ntransmitted && options.pingcount
1643 && nreceived >= options.pingcount) {
1644 ping_finish();
1645 if (!options.createif)
1646 state = 3;
1647 }
jjako7b8fad42003-07-07 14:37:42 +00001648
Harald Weltebed35df2011-11-02 13:06:18 +01001649 /* Send off disconnect */
1650 if (3 == state) {
1651 state = 4;
1652 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1653 for (n = 0; n < options.contexts; n++) {
1654 /* Delete context */
1655 printf("Disconnecting PDP context #%d\n", n);
1656 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1657 1);
1658 if ((options.pinghost.s_addr != 0)
1659 && ntransmitted)
1660 ping_finish();
1661 }
1662 }
jjako7b8fad42003-07-07 14:37:42 +00001663
Harald Weltebed35df2011-11-02 13:06:18 +01001664 /* Send of ping packets */
1665 diff = 0;
1666 while ((diff <= 0) &&
1667 /* Send off an ICMP ping packet */
1668 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1669 ((pingseq < options.pingcount)
1670 || (options.pingcount == 0))) {
1671 if (!pingseq)
1672 gettimeofday(&firstping, &tz); /* Set time of first ping */
1673 gettimeofday(&tv, &tz);
1674 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1675 if (diff <= 0) {
1676 if (options.debug)
1677 printf("Create_ping %d\n", diff);
1678 create_ping(gsn,
1679 iparr[pingseq %
1680 options.contexts].pdp,
1681 &options.pinghost, pingseq,
1682 options.pingsize);
1683 pingseq++;
1684 }
1685 }
jjako5da68452003-01-28 16:08:47 +00001686
Harald Weltebed35df2011-11-02 13:06:18 +01001687 FD_ZERO(&fds);
1688 if (tun)
1689 FD_SET(tun->fd, &fds);
1690 FD_SET(gsn->fd0, &fds);
1691 FD_SET(gsn->fd1c, &fds);
1692 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001693
Harald Weltebed35df2011-11-02 13:06:18 +01001694 gtp_retranstimeout(gsn, &idleTime);
1695 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001696
Harald Weltebed35df2011-11-02 13:06:18 +01001697 if (options.debug)
1698 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1699 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001700
bjovana8f71eb2017-02-24 17:39:20 +01001701 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001702 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1703 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001704 if (errno == EINTR)
1705 signal_received = 1;
1706 else
1707 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1708 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001709 break;
1710 case 0:
1711 gtp_retrans(gsn); /* Only retransmit if nothing else */
1712 break;
1713 default:
1714 break;
1715 }
1716
bjovana8f71eb2017-02-24 17:39:20 +01001717 if (!signal_received) {
1718
1719 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1720 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1721 "TUN decaps failed");
1722 }
1723
1724 if (FD_ISSET(gsn->fd0, &fds))
1725 gtp_decaps0(gsn);
1726
1727 if (FD_ISSET(gsn->fd1c, &fds))
1728 gtp_decaps1c(gsn);
1729
1730 if (FD_ISSET(gsn->fd1u, &fds))
1731 gtp_decaps1u(gsn);
1732
Harald Weltebed35df2011-11-02 13:06:18 +01001733 }
Harald Weltebed35df2011-11-02 13:06:18 +01001734 }
1735
1736 gtp_free(gsn); /* Clean up the gsn instance */
1737
1738 if (options.createif)
1739 tun_free(tun);
1740
1741 if (0 == state)
1742 exit(1); /* Indicate error */
1743
1744 return 0;
jjako52c24142002-12-16 13:33:51 +00001745}