blob: c181603dc4ac2da12813146581a68ff22b7c36aa [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;
Harald Welte840a8e92017-09-24 18:12:40 +0800121 uint8_t pdp_type;
jjakoa7cd2492003-04-11 09:40:12 +0000122} options;
jjako52c24142002-12-16 13:33:51 +0000123
jjako5da68452003-01-28 16:08:47 +0000124/* Definitions to use for PING. Most of the ping code was derived from */
125/* the original ping program by Mike Muuss */
126
127/* IP header and ICMP echo header */
128#define CREATEPING_MAX 2048
129#define CREATEPING_IP 20
130#define CREATEPING_ICMP 8
131
132struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100133 uint8_t ipver; /* Type and header length */
134 uint8_t tos; /* Type of Service */
135 uint16_t length; /* Total length */
136 uint16_t fragid; /* Identifier */
137 uint16_t offset; /* Flags and fragment offset */
138 uint8_t ttl; /* Time to live */
139 uint8_t protocol; /* Protocol */
140 uint16_t ipcheck; /* Header checksum */
141 uint32_t src; /* Source address */
142 uint32_t dst; /* Destination */
143 uint8_t type; /* Type and header length */
144 uint8_t code; /* Code */
145 uint16_t checksum; /* Header checksum */
146 uint16_t ident; /* Identifier */
147 uint16_t seq; /* Sequence number */
148 uint8_t data[CREATEPING_MAX]; /* Data */
149} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000150
151/* Statistical values for ping */
152int nreceived = 0;
153int ntreceived = 0;
154int ntransmitted = 0;
155int tmin = 999999999;
156int tmax = 0;
157int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100158int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000159struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000160
bjovana8f71eb2017-02-24 17:39:20 +0100161void signal_handler(int signo)
162{
163 if (state == 2)
164 state = 3; /* Tell main loop to finish. */
165}
166
Harald Welted12eab92017-08-02 19:49:47 +0200167int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100168{
Harald Welted12eab92017-08-02 19:49:47 +0200169 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100170 struct iphash_t *h;
171 struct iphash_t *prev = NULL;
172 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200173 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100174 for (h = iphash[hash]; h; h = h->ipnext)
175 prev = h;
176 if (!prev)
177 iphash[hash] = ipaddr;
178 else
179 prev->ipnext = ipaddr;
180 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000181}
182
Harald Weltebed35df2011-11-02 13:06:18 +0100183int ipdel(struct iphash_t *ipaddr)
184{
Harald Welted12eab92017-08-02 19:49:47 +0200185 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100186 struct iphash_t *h;
187 struct iphash_t *prev = NULL;
188 for (h = iphash[hash]; h; h = h->ipnext) {
189 if (h == ipaddr) {
190 if (!prev)
191 iphash[hash] = h->ipnext;
192 else
193 prev->ipnext = h->ipnext;
194 return 0;
195 }
196 prev = h;
197 }
198 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000199}
200
Harald Welted12eab92017-08-02 19:49:47 +0200201int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100202{
Harald Welted12eab92017-08-02 19:49:47 +0200203 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100204 struct iphash_t *h;
205 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200206 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100207 *ipaddr = h;
208 return 0;
209 }
210 }
211 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000212}
213
jjakoa7cd2492003-04-11 09:40:12 +0000214/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +0100215void log_pid(char *pidfile)
216{
217 FILE *file;
218 mode_t oldmask;
219
220 oldmask = umask(022);
221 file = fopen(pidfile, "w");
222 umask(oldmask);
223 if (!file)
224 return;
225 fprintf(file, "%d\n", (int)getpid());
226 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000227}
228
Harald Weltebed35df2011-11-02 13:06:18 +0100229int process_options(int argc, char **argv)
230{
231 /* gengeopt declarations */
232 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000233
Harald Weltebed35df2011-11-02 13:06:18 +0100234 struct hostent *host;
235 unsigned int n;
236 uint16_t i;
237 uint8_t a;
238 uint8_t b;
239 char *tmp;
240 char *pch;
241 char *type;
242 char *mcc;
243 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100244 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100245 char *lac;
246 int lac_d;
247 char *rest;
248 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
249 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
250 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
251 int sign;
252 int nbquarters;
253 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000254
Harald Weltebed35df2011-11-02 13:06:18 +0100255 if (cmdline_parser(argc, argv, &args_info) != 0)
256 return -1;
257 if (args_info.debug_flag) {
258 if (args_info.remote_arg)
259 printf("remote: %s\n", args_info.remote_arg);
260 if (args_info.listen_arg)
261 printf("listen: %s\n", args_info.listen_arg);
262 if (args_info.conf_arg)
263 printf("conf: %s\n", args_info.conf_arg);
264 printf("debug: %d\n", args_info.debug_flag);
265 if (args_info.imsi_arg)
266 printf("imsi: %s\n", args_info.imsi_arg);
267 printf("qos: %#08x\n", args_info.qos_arg);
268 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
269 printf("qose2: %#04x\n", args_info.qose2_arg);
270 printf("qose3: %#06x\n", args_info.qose3_arg);
271 printf("qose4: %#06x\n", args_info.qose4_arg);
272 printf("charging: %#04x\n", args_info.charging_arg);
273 if (args_info.apn_arg)
274 printf("apn: %s\n", args_info.apn_arg);
275 if (args_info.msisdn_arg)
276 printf("msisdn: %s\n", args_info.msisdn_arg);
277 if (args_info.uid_arg)
278 printf("uid: %s\n", args_info.uid_arg);
279 if (args_info.pwd_arg)
280 printf("pwd: %s\n", args_info.pwd_arg);
281 if (args_info.pidfile_arg)
282 printf("pidfile: %s\n", args_info.pidfile_arg);
283 if (args_info.statedir_arg)
284 printf("statedir: %s\n", args_info.statedir_arg);
285 if (args_info.dns_arg)
286 printf("dns: %s\n", args_info.dns_arg);
287 printf("contexts: %d\n", args_info.contexts_arg);
288 printf("timelimit: %d\n", args_info.timelimit_arg);
289 printf("createif: %d\n", args_info.createif_flag);
290 if (args_info.ipup_arg)
291 printf("ipup: %s\n", args_info.ipup_arg);
292 if (args_info.ipdown_arg)
293 printf("ipdown: %s\n", args_info.ipdown_arg);
294 printf("defaultroute: %d\n", args_info.defaultroute_flag);
295 if (args_info.pinghost_arg)
296 printf("pinghost: %s\n", args_info.pinghost_arg);
297 printf("pingrate: %d\n", args_info.pingrate_arg);
298 printf("pingsize: %d\n", args_info.pingsize_arg);
299 printf("pingcount: %d\n", args_info.pingcount_arg);
300 printf("pingquiet: %d\n", args_info.pingquiet_flag);
301 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800302 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100303 }
jjakoa7cd2492003-04-11 09:40:12 +0000304
Harald Weltebed35df2011-11-02 13:06:18 +0100305 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000306
Harald Weltebed35df2011-11-02 13:06:18 +0100307 if (args_info.conf_arg) {
308 if (cmdline_parser_configfile
309 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
310 return -1;
311 if (args_info.debug_flag) {
312 printf("cmdline_parser_configfile\n");
313 if (args_info.remote_arg)
314 printf("remote: %s\n", args_info.remote_arg);
315 if (args_info.listen_arg)
316 printf("listen: %s\n", args_info.listen_arg);
317 if (args_info.conf_arg)
318 printf("conf: %s\n", args_info.conf_arg);
319 printf("debug: %d\n", args_info.debug_flag);
320 if (args_info.imsi_arg)
321 printf("imsi: %s\n", args_info.imsi_arg);
322 printf("qos: %#08x\n", args_info.qos_arg);
323 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
324 printf("qose2: %#04x\n", args_info.qose2_arg);
325 printf("qose3: %#06x\n", args_info.qose3_arg);
326 printf("qose4: %#06x\n", args_info.qose4_arg);
327 printf("charging: %#04x\n", args_info.charging_arg);
328 if (args_info.apn_arg)
329 printf("apn: %s\n", args_info.apn_arg);
330 if (args_info.msisdn_arg)
331 printf("msisdn: %s\n", args_info.msisdn_arg);
332 if (args_info.uid_arg)
333 printf("uid: %s\n", args_info.uid_arg);
334 if (args_info.pwd_arg)
335 printf("pwd: %s\n", args_info.pwd_arg);
336 if (args_info.pidfile_arg)
337 printf("pidfile: %s\n", args_info.pidfile_arg);
338 if (args_info.statedir_arg)
339 printf("statedir: %s\n",
340 args_info.statedir_arg);
341 if (args_info.dns_arg)
342 printf("dns: %s\n", args_info.dns_arg);
343 printf("contexts: %d\n", args_info.contexts_arg);
344 printf("timelimit: %d\n", args_info.timelimit_arg);
345 printf("createif: %d\n", args_info.createif_flag);
346 if (args_info.ipup_arg)
347 printf("ipup: %s\n", args_info.ipup_arg);
348 if (args_info.ipdown_arg)
349 printf("ipdown: %s\n", args_info.ipdown_arg);
350 printf("defaultroute: %d\n",
351 args_info.defaultroute_flag);
352 if (args_info.pinghost_arg)
353 printf("pinghost: %s\n",
354 args_info.pinghost_arg);
355 printf("pingrate: %d\n", args_info.pingrate_arg);
356 printf("pingsize: %d\n", args_info.pingsize_arg);
357 printf("pingcount: %d\n", args_info.pingcount_arg);
358 printf("pingquiet: %d\n", args_info.pingquiet_flag);
359 printf("norecovery: %d\n", args_info.norecovery_flag);
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800360 printf("no-tx-gpdu-seq: %d\n", args_info.no_tx_gpdu_seq_flag);
Harald Weltebed35df2011-11-02 13:06:18 +0100361 }
362 }
jjako193e8b12003-11-10 12:31:41 +0000363
Harald Weltebed35df2011-11-02 13:06:18 +0100364 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000365
Harald Weltebed35df2011-11-02 13:06:18 +0100366 /* foreground */
367 /* If fg flag not given run as a daemon */
368 /* Do not allow sgsnemu to run as deamon
369 if (!args_info.fg_flag)
370 {
371 closelog();
372 freopen("/dev/null", "w", stdout);
373 freopen("/dev/null", "w", stderr);
374 freopen("/dev/null", "r", stdin);
375 daemon(0, 0);
376 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
377 } */
jjako1a51df72004-07-20 08:30:21 +0000378
Harald Weltebed35df2011-11-02 13:06:18 +0100379 /* debug */
380 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000381
Harald Weltebed35df2011-11-02 13:06:18 +0100382 /* pidfile */
383 /* This has to be done after we have our final pid */
384 if (args_info.pidfile_arg) {
385 log_pid(args_info.pidfile_arg);
386 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200387
Harald Weltebed35df2011-11-02 13:06:18 +0100388 /* dns */
389 /* If no dns option is given use system default */
390 /* Do hostname lookup to translate hostname to IP address */
391 printf("\n");
392 if (args_info.dns_arg) {
393 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100394 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100395 "Invalid DNS address: %s!", args_info.dns_arg);
396 return -1;
397 } else {
398 memcpy(&options.dns.s_addr, host->h_addr,
399 host->h_length);
400 _res.nscount = 1;
401 _res.nsaddr_list[0].sin_addr = options.dns;
402 printf("Using DNS server: %s (%s)\n",
403 args_info.dns_arg, inet_ntoa(options.dns));
404 }
405 } else {
406 options.dns.s_addr = 0;
407 printf("Using default DNS server\n");
408 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200409
Harald Weltebed35df2011-11-02 13:06:18 +0100410 /* listen */
411 /* If no listen option is specified listen to any local port */
412 /* Do hostname lookup to translate hostname to IP address */
413 if (args_info.listen_arg) {
414 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100415 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100416 "Invalid listening address: %s!",
417 args_info.listen_arg);
418 return -1;
419 } else {
420 memcpy(&options.listen.s_addr, host->h_addr,
421 host->h_length);
422 printf("Local IP address is: %s (%s)\n",
423 args_info.listen_arg, inet_ntoa(options.listen));
424 }
425 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100426 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100427 "Listening address must be specified: %s!",
428 args_info.listen_arg);
429 return -1;
430 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200431
Harald Weltebed35df2011-11-02 13:06:18 +0100432 /* remote */
433 /* If no remote option is specified terminate */
434 /* Do hostname lookup to translate hostname to IP address */
435 if (args_info.remote_arg) {
436 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100437 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100438 "Invalid remote address: %s!",
439 args_info.remote_arg);
440 return -1;
441 } else {
442 memcpy(&options.remote.s_addr, host->h_addr,
443 host->h_length);
444 printf("Remote IP address is: %s (%s)\n",
445 args_info.remote_arg, inet_ntoa(options.remote));
446 }
447 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100448 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100449 "No remote address given!");
450 return -1;
451 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200452
Harald Weltebed35df2011-11-02 13:06:18 +0100453 /* imsi */
454 if (strlen(args_info.imsi_arg) != 15) {
455 printf("Invalid IMSI\n");
456 return -1;
457 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200458
Harald Weltebed35df2011-11-02 13:06:18 +0100459 options.imsi = 0xf000000000000000ull;
460 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
461 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
462 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
463 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
464 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
465 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
466 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
467 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
468 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
469 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
470 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
471 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
472 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
473 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
474 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200475
Harald Weltebed35df2011-11-02 13:06:18 +0100476 printf("IMSI is: %s (%#08llx)\n",
477 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200478
Harald Weltebed35df2011-11-02 13:06:18 +0100479 /* nsapi */
480 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
481 printf("Invalid NSAPI\n");
482 return -1;
483 }
484 options.nsapi = args_info.nsapi_arg;
485 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200486
Harald Weltebed35df2011-11-02 13:06:18 +0100487 /* qos */
488 options.qos.l = 4;
489 options.qos.v[3] = (args_info.qos_arg) & 0xff;
490 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
491 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
492 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
493 /* Extensions according to 3GPP TS 24.008 */
494 if (args_info.qose1_given == 1) {
495 options.qos.l = 12;
496 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
497 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
498 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
499 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
500 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
501 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
502 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
503 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
504 if (args_info.qose2_given == 1) {
505 options.qos.l = 13;
506 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
507 if (args_info.qose3_given == 1) {
508 options.qos.l = 15;
509 options.qos.v[14] =
510 (args_info.qose3_arg) & 0xff;
511 options.qos.v[13] =
512 ((args_info.qose3_arg) >> 8) & 0xff;
513 if (args_info.qose4_given == 1) {
514 options.qos.l = 17;
515 options.qos.v[16] =
516 (args_info.qose4_arg) & 0xff;
517 options.qos.v[15] =
518 ((args_info.qose4_arg) >> 8) & 0xff;
519 }
520 }
521 }
522 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200523
Harald Weltebed35df2011-11-02 13:06:18 +0100524 /* charging */
525 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200526
Harald Weltebed35df2011-11-02 13:06:18 +0100527 /* contexts */
528 if (args_info.contexts_arg > MAXCONTEXTS) {
529 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
530 return -1;
531 }
532 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200533
Harald Weltebed35df2011-11-02 13:06:18 +0100534 /* Timelimit */
535 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200536
Harald Weltebed35df2011-11-02 13:06:18 +0100537 /* gtpversion */
538 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
539 printf("Invalid GTP version\n");
540 return -1;
541 }
542 options.gtpversion = args_info.gtpversion_arg;
543 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200544
Harald Weltebed35df2011-11-02 13:06:18 +0100545 /* apn */
546 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
547 printf("Invalid APN\n");
548 return -1;
549 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100550 options.apn.l = strlen(args_info.apn_arg) + 1;
551
552 apn = (char *)options.apn.v;
553 for (tok = strtok(args_info.apn_arg, ".");
554 tok != NULL;
555 tok = strtok(NULL, ".")) {
556 size_t len = strlen(tok);
557
558 *apn++ = (char)len;
559 strncpy(apn, tok, len);
560 apn += len;
561 }
562
Harald Weltebed35df2011-11-02 13:06:18 +0100563 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200564
Harald Weltebed35df2011-11-02 13:06:18 +0100565 /* selmode */
566 options.selmode = args_info.selmode_arg;
567 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200568
Harald Weltebed35df2011-11-02 13:06:18 +0100569 /* rattype */
570 if (args_info.rattype_given == 1) {
571 options.rattype_given = 1;
Harald Weltef6214982017-09-24 10:23:24 +0800572 options.rattype.l = 1;
573 options.rattype.v[0] = args_info.rattype_arg;
574 printf("Using RAT Type: %d\n", args_info.rattype_arg);
Harald Weltebed35df2011-11-02 13:06:18 +0100575 }
Harald Welte41af5692011-10-07 18:42:34 +0200576
Harald Weltebed35df2011-11-02 13:06:18 +0100577 /* userloc */
578 if (args_info.userloc_given == 1) {
579 printf("Using User Location Information: %s\n",
580 args_info.userloc_arg);
581 tmp = args_info.userloc_arg;
582 n = 0;
583 pch = strtok(tmp, ".");
584 while (pch != NULL) {
585 userloc_el[n] = pch;
586 pch = strtok(NULL, ".");
587 n++;
588 }
Harald Welte41af5692011-10-07 18:42:34 +0200589
Harald Weltebed35df2011-11-02 13:06:18 +0100590 options.userloc_given = 1;
591 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200592
Harald Weltebed35df2011-11-02 13:06:18 +0100593 /* 3GPP Geographic Location Type t0 / t1 / t2 */
594 type = userloc_el[0];
595 printf("->type : %c\n", type[0]);
596 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
597 printf("Invalid type \n");
598 return -1;
599 }
600 /* options.userloc.v[0] = 0x00 */
601 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200602
Harald Weltebed35df2011-11-02 13:06:18 +0100603 /* MCC */
604 mcc = userloc_el[1];
605 printf("->mcc : %s\n", mcc);
606 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200607 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100608 return -1;
609 }
Harald Welte41af5692011-10-07 18:42:34 +0200610
Harald Weltebed35df2011-11-02 13:06:18 +0100611 /* MNC */
612 mnc = userloc_el[2];
613 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200614
Harald Weltebed35df2011-11-02 13:06:18 +0100615 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
616 /* options.userloc.v[1] = 0x52 */
617 a = (uint8_t) (mcc[0] - 48);
618 b = (uint8_t) (mcc[1] - 48);
619 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200620
Harald Weltebed35df2011-11-02 13:06:18 +0100621 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
622 /* options.userloc.v[2] = 0xf0 */
623 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200624
Harald Weltebed35df2011-11-02 13:06:18 +0100625 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200626 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100627 return -1;
628 }
629 if (strlen(mnc) == 2) {
630 b = 15;
631 }
632 if (strlen(mnc) == 3) {
633 b = (uint8_t) (mnc[2] - 48);
634 }
635 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200636
Harald Weltebed35df2011-11-02 13:06:18 +0100637 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
638 /* options.userloc.v[3] = 0x99 */
639 a = (uint8_t) (mnc[0] - 48);
640 b = (uint8_t) (mnc[1] - 48);
641 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200642
Harald Weltebed35df2011-11-02 13:06:18 +0100643 /* LAC */
644 lac = userloc_el[3];
645 /*options.userloc.v[4] = 0x12 ; */
646 /*options.userloc.v[5] = 0x10 ; */
647 printf("->LAC: %s\n", lac);
648 lac_d = atoi(lac);
649 if (lac_d > 65535 || lac_d < 1) {
650 printf("Invalid LAC\n");
651 return -1;
652 }
653 i = lac_d >> 8;
654 options.userloc.v[4] = i; /* octet 8 - LAC */
655 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200656
Harald Weltebed35df2011-11-02 13:06:18 +0100657 /* CI/SAC/RAC */
658 rest = userloc_el[4];
659 printf("->CI/SAC/RAC : %s\n", rest);
660 lac_d = atoi(rest);
661 if (lac_d > 65535 || lac_d < 1) {
662 printf("Invalid CI/SAC/RAC\n");
663 return -1;
664 }
665 /*options.userloc.v[6] = 0x04 ; */
666 /*options.userloc.v[7] = 0xb7 ; */
667 i = lac_d >> 8;
668 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
669 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
670 }
jjakoa7cd2492003-04-11 09:40:12 +0000671
Harald Weltebed35df2011-11-02 13:06:18 +0100672 /* RAI */
673 if (args_info.rai_given == 1) {
674 printf("Using RAI: %s\n", args_info.rai_arg);
675 tmp = args_info.rai_arg;
676 n = 0;
677 pch = strtok(tmp, ".");
678 while (pch != NULL) {
679 rai_el[n] = pch;
680 pch = strtok(NULL, ".");
681 n++;
682 }
jjakoa7cd2492003-04-11 09:40:12 +0000683
Harald Weltebed35df2011-11-02 13:06:18 +0100684 options.rai_given = 1;
685 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000686
Harald Weltebed35df2011-11-02 13:06:18 +0100687 /* MCC */
688 mcc = rai_el[0];
689 printf("->mcc : %s\n", mcc);
690 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200691 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100692 return -1;
693 }
694
695 /* MNC */
696 mnc = rai_el[1];
697 printf("->mnc : %s\n", mnc);
698
699 a = (uint8_t) (mcc[0] - 48);
700 b = (uint8_t) (mcc[1] - 48);
701 options.rai.v[0] = 16 * b + a;
702
703 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
704 a = (uint8_t) (mcc[2] - 48);
705
706 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200707 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100708 return -1;
709 }
710 if (strlen(mnc) == 2) {
711 b = 15;
712 }
713 if (strlen(mnc) == 3) {
714 b = (uint8_t) (mnc[2] - 48);
715 }
716 options.rai.v[1] = 16 * b + a;
717
718 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
719 a = (uint8_t) (mnc[0] - 48);
720 b = (uint8_t) (mnc[1] - 48);
721 options.rai.v[2] = 16 * b + a;
722
723 /* LAC */
724 lac = rai_el[2];
725 printf("->LAC: %s\n", lac);
726 lac_d = atoi(lac);
727 if (lac_d > 65535 || lac_d < 1) {
728 printf("Invalid LAC\n");
729 return -1;
730 }
731 i = lac_d >> 8;
732 options.rai.v[3] = i; /* octet 5 - LAC */
733 options.rai.v[4] = lac_d; /* octet 6 - LAC */
734
735 /* RAC */
736 rest = rai_el[3];
737 printf("->RAC : %s\n", rest);
738 lac_d = atoi(rest);
739 if (lac_d > 255 || lac_d < 1) {
740 printf("Invalid RAC\n");
741 return -1;
742 }
743 options.rai.v[5] = lac_d; /* octet 7 - RAC */
744 }
745
746 /* mstz */
747 if (args_info.mstz_given == 1) {
748 options.mstz_given = 1;
749 options.mstz.l = 2;
750
751 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
752 tmp = args_info.mstz_arg;
753 n = 0;
754 pch = strtok(tmp, ".");
755 while (pch != NULL) {
756 mstz_el[n] = pch;
757 pch = strtok(NULL, ".");
758 n++;
759 }
760
761 /* sign */
762 sign = atoi(mstz_el[0]);
763 printf("->Sign (0=+ / 1=-): %d\n", sign);
764 if (sign != 0 && sign != 1) {
765 printf("Invalid Sign \n");
766 return -1;
767 }
768 /* nbquarters */
769 nbquarters = atoi(mstz_el[1]);
770 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
771 if (nbquarters < 0 || nbquarters > 79) {
772 printf("Invalid Number of Quarters \n");
773 return -1;
774 }
775 /* DST */
776 DST = atoi(mstz_el[2]);
777 printf("->Daylight Saving Time Adjustment : %d\n", DST);
778 if (DST < 0 || DST > 3) {
779 printf("Invalid DST Adjustment \n");
780 return -1;
781 }
782 /* 12345678
783 bits 123 = unit of # of quarters of an hour
784 bits 678 = # of quarters of an hour / 10
785 bit 5 = sign
786 */
787 i = nbquarters % 10;
788 i = i << 4;
789 i = i + nbquarters / 10 + 8 * sign;
790 /* options.mstz.v[0] = 0x69 ; */
791 /* options.mstz.v[1] = 0x01 ; */
792 options.mstz.v[0] = i;
793 options.mstz.v[1] = DST;
794 n = (i & 0x08) ? '-' : '+';
795 printf
796 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
797 n, nbquarters / 4, nbquarters % 4 * 15);
798 }
799
800 /* imeisv */
801 if (args_info.imeisv_given == 1) {
802 options.imeisv_given = 1;
803 if (strlen(args_info.imeisv_arg) != 16) {
804 printf("Invalid IMEI(SV)\n");
805 return -1;
806 }
807 options.imeisv.l = 8;
808 for (n = 0; n < 8; n++) {
809 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
810 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
811 options.imeisv.v[n] = 16 * b + a;
812 }
813 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
814 }
815
816 /* msisdn */
817 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
818 printf("Invalid MSISDN\n");
819 return -1;
820 }
821 options.msisdn.l = 1;
822 options.msisdn.v[0] = 0x91; /* International format */
823 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
824 if ((n % 2) == 0) {
825 options.msisdn.v[((int)n / 2) + 1] =
826 args_info.msisdn_arg[n] - 48 + 0xf0;
827 options.msisdn.l += 1;
828 } else {
829 options.msisdn.v[((int)n / 2) + 1] =
830 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
831 (args_info.msisdn_arg[n] - 48) * 16;
832 }
833 }
834 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
835
836 /* UID and PWD */
837 /* Might need to also insert stuff like DNS etc. */
838 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
839 (sizeof(options.pco.v) - 1)) {
840 printf("invalid UID and PWD\n");
841 return -1;
842 }
843 options.pco.l =
844 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
845 options.pco.v[0] = 0x80; /* PPP */
846 options.pco.v[1] = 0xc0; /* PAP */
847 options.pco.v[2] = 0x23;
848 options.pco.v[3] =
849 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
850 options.pco.v[4] = 0x01; /* Authenticate request */
851 options.pco.v[5] = 0x01;
852 options.pco.v[6] = 0x00; /* MSB of length */
853 options.pco.v[7] =
854 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
855 options.pco.v[8] = strlen(args_info.uid_arg);
856 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
857 options.pco.v[9 + strlen(args_info.uid_arg)] =
858 strlen(args_info.pwd_arg);
859 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
860 args_info.pwd_arg, strlen(args_info.pwd_arg));
861
862 /* createif */
863 options.createif = args_info.createif_flag;
864
865 /* net */
866 /* Store net as in_addr net and mask */
867 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200868 struct in46_addr in46;
Harald Weltebed35df2011-11-02 13:06:18 +0100869 if (ippool_aton
Harald Welted12eab92017-08-02 19:49:47 +0200870 (&in46, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100871 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100872 "Invalid network address: %s!",
873 args_info.net_arg);
874 exit(1);
875 }
Harald Welted12eab92017-08-02 19:49:47 +0200876 options.net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100877 options.netaddr.s_addr = options.net.s_addr;
878 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000879
Harald Weltebed35df2011-11-02 13:06:18 +0100880 } else {
881 options.net.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200882 options.prefixlen = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100883 options.netaddr.s_addr = 0;
884 options.destaddr.s_addr = 0;
885 }
jjako193e8b12003-11-10 12:31:41 +0000886
Harald Weltebed35df2011-11-02 13:06:18 +0100887 /* ipup */
888 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000889
Harald Weltebed35df2011-11-02 13:06:18 +0100890 /* ipdown */
891 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000892
Harald Weltebed35df2011-11-02 13:06:18 +0100893 /* statedir */
894 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000895
Harald Weltebed35df2011-11-02 13:06:18 +0100896 /* defaultroute */
897 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000898
Harald Weltebed35df2011-11-02 13:06:18 +0100899 /* pinghost */
900 /* Store ping host as in_addr */
901 if (args_info.pinghost_arg) {
902 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100903 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100904 "Invalid ping host: %s!",
905 args_info.pinghost_arg);
906 return -1;
907 } else {
908 memcpy(&options.pinghost.s_addr, host->h_addr,
909 host->h_length);
910 printf("Using ping host: %s (%s)\n",
911 args_info.pinghost_arg,
912 inet_ntoa(options.pinghost));
913 }
914 }
jjakoa7cd2492003-04-11 09:40:12 +0000915
Harald Weltebed35df2011-11-02 13:06:18 +0100916 /* Other ping parameters */
917 options.pingrate = args_info.pingrate_arg;
918 options.pingsize = args_info.pingsize_arg;
919 options.pingcount = args_info.pingcount_arg;
920 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000921
Harald Weltebed35df2011-11-02 13:06:18 +0100922 /* norecovery */
923 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000924
Harald Weltefbb9c7f2017-09-24 11:50:20 +0800925 if (args_info.no_tx_gpdu_seq_flag)
926 options.tx_gpdu_seq = 0;
927 else
928 options.tx_gpdu_seq = 1;
929
Harald Welte840a8e92017-09-24 18:12:40 +0800930 /* PDP Type */
931 if (!strcmp(args_info.pdp_type_arg, "v6"))
932 options.pdp_type = PDP_EUA_TYPE_v6;
933 else
934 options.pdp_type = PDP_EUA_TYPE_v4;
935
Harald Weltebed35df2011-11-02 13:06:18 +0100936 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000937
938}
939
Harald Weltebed35df2011-11-02 13:06:18 +0100940int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
941{
942 unsigned int i;
943 printf("The packet looks like this:\n");
944 for (i = 0; i < len; i++) {
945 printf("%02x ", (unsigned char)*(char *)(pack + i));
946 if (!((i + 1) % 16))
947 printf("\n");
948 };
949 printf("\n");
950 return 0;
jjako52c24142002-12-16 13:33:51 +0000951}
952
Harald Weltebed35df2011-11-02 13:06:18 +0100953char *print_ipprot(int t)
954{
955 switch (t) {
956 case 1:
957 return "ICMP";
958 case 6:
959 return "TCP";
960 case 17:
961 return "UDP";
962 default:
963 return "Unknown";
964 };
jjako5da68452003-01-28 16:08:47 +0000965}
966
Harald Weltebed35df2011-11-02 13:06:18 +0100967char *print_icmptype(int t)
968{
969 static char *ttab[] = {
970 "Echo Reply",
971 "ICMP 1",
972 "ICMP 2",
973 "Dest Unreachable",
974 "Source Quench",
975 "Redirect",
976 "ICMP 6",
977 "ICMP 7",
978 "Echo",
979 "ICMP 9",
980 "ICMP 10",
981 "Time Exceeded",
982 "Parameter Problem",
983 "Timestamp",
984 "Timestamp Reply",
985 "Info Request",
986 "Info Reply"
987 };
988 if (t < 0 || t > 16)
989 return ("OUT-OF-RANGE");
990 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +0000991}
992
Harald Weltebed35df2011-11-02 13:06:18 +0100993int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
994{
995 unsigned int n;
996 uint64_t i64 = 0;
997 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
998 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +0000999
Harald Weltebed35df2011-11-02 13:06:18 +01001000 /* Convert to uint64_t from ul16_t format (most significant digit first) */
1001 /* ul16_t format always starts with 0x91 to indicate international format */
1002 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
1003 for (n = 0; n < src->l; n++) {
1004 if ((src->v[n] & 0x0f) != 0x0f) {
1005 i64 *= 10;
1006 i64 += src->v[n] & 0x0f;
1007 }
1008 if ((src->v[n] & 0xf0) != 0xf0) {
1009 i64 *= 10;
1010 i64 += (src->v[n] & 0xf0) >> 4;
1011 }
1012 }
jjako193e8b12003-11-10 12:31:41 +00001013
Harald Weltebed35df2011-11-02 13:06:18 +01001014 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001015
Harald Weltebed35df2011-11-02 13:06:18 +01001016 /* Generate array with least significant digit in first octet */
1017 while (i64) {
1018 msa[msalen++] = i64 % 10;
1019 i64 = i64 / 10;
1020 }
jjako193e8b12003-11-10 12:31:41 +00001021
Harald Weltebed35df2011-11-02 13:06:18 +01001022 /* Convert back to ul16_t format */
1023 for (n = 0; n < msalen; n++) {
1024 if ((n % 2) == 0) {
1025 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1026 dst->l += 1;
1027 } else {
1028 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1029 msa[msalen - n - 1] * 16;
1030 }
1031 }
jjako193e8b12003-11-10 12:31:41 +00001032
Harald Weltebed35df2011-11-02 13:06:18 +01001033 return 0;
jjako193e8b12003-11-10 12:31:41 +00001034
1035}
1036
Harald Weltebed35df2011-11-02 13:06:18 +01001037int imsi_add(uint64_t src, uint64_t * dst, int add)
1038{
1039 /* TODO: big endian / small endian ??? */
1040 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001041
Harald Weltebed35df2011-11-02 13:06:18 +01001042 /* Convert from uint64_t bcd to uint64_t integer format */
1043 /* The resulting integer format is multiplied by 10 */
1044 while (src) {
1045 if ((src & 0x0f) != 0x0f) {
1046 i64 *= 10;
1047 i64 += (src & 0x0f);
1048 }
1049 if ((src & 0xf0) != 0xf0) {
1050 i64 *= 10;
1051 i64 += (src & 0xf0) >> 4;
1052 }
1053 src = src >> 8;
1054 }
jjako193e8b12003-11-10 12:31:41 +00001055
Harald Weltebed35df2011-11-02 13:06:18 +01001056 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001057
Harald Weltebed35df2011-11-02 13:06:18 +01001058 *dst = 0;
1059 while (i64) {
1060 *dst = *dst << 4;
1061 *dst += (i64 % 10);
1062 i64 = i64 / 10;
1063 }
jjako193e8b12003-11-10 12:31:41 +00001064
Harald Weltebed35df2011-11-02 13:06:18 +01001065 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001066
Harald Weltebed35df2011-11-02 13:06:18 +01001067 return 0;
jjako193e8b12003-11-10 12:31:41 +00001068
1069}
1070
jjakoafb2a972003-01-29 21:04:13 +00001071/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001072int ping_timeout(struct timeval *tp)
1073{
1074 struct timezone tz;
1075 struct timeval tv;
1076 int diff;
1077 if ((options.pinghost.s_addr) && (2 == state) &&
1078 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1079 gettimeofday(&tv, &tz);
1080 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1081 tp->tv_sec = 0;
1082 if (diff > 0)
1083 tp->tv_usec = diff;
1084 else {
1085 /* For some reason we get packet loss if set to zero */
1086 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1087 tp->tv_usec = 0;
1088 }
1089 }
1090 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001091}
1092
jjako5da68452003-01-28 16:08:47 +00001093/* Print out statistics when at the end of ping sequence */
1094int ping_finish()
1095{
Harald Weltebed35df2011-11-02 13:06:18 +01001096 struct timezone tz;
1097 struct timeval tv;
1098 int elapsed;
1099 gettimeofday(&tv, &tz);
1100 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1101 printf("\n");
1102 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1103 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1104 elapsed / 1000000.0);
1105 printf("%d packets received, ", nreceived);
1106 if (ntransmitted) {
1107 if (nreceived > ntransmitted)
1108 printf("-- somebody's printing up packets!");
1109 else
1110 printf("%d%% packet loss",
1111 (int)(((ntransmitted - nreceived) * 100) /
1112 ntransmitted));
1113 }
1114 printf("\n");
1115 if (options.debug)
1116 printf("%d packets received in total\n", ntreceived);
1117 if (nreceived && tsum)
1118 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1119 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1120 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001121
Harald Weltebed35df2011-11-02 13:06:18 +01001122 ntransmitted = 0;
1123 return 0;
jjako5da68452003-01-28 16:08:47 +00001124}
1125
1126/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001127int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1128{
1129 struct timezone tz;
1130 struct timeval tv;
1131 struct timeval *tp;
1132 struct ip_ping *pingpack = pack;
1133 struct in_addr src;
1134 int triptime;
jjako5da68452003-01-28 16:08:47 +00001135
Harald Weltebed35df2011-11-02 13:06:18 +01001136 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001137
Harald Weltebed35df2011-11-02 13:06:18 +01001138 gettimeofday(&tv, &tz);
1139 if (options.debug)
1140 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001141
Harald Weltebed35df2011-11-02 13:06:18 +01001142 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1143 printf("packet too short (%d bytes) from %s\n", len,
1144 inet_ntoa(src));
1145 return 0;
1146 }
jjako5da68452003-01-28 16:08:47 +00001147
Harald Weltebed35df2011-11-02 13:06:18 +01001148 ntreceived++;
1149 if (pingpack->protocol != 1) {
1150 if (!options.pingquiet)
1151 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1152 len, inet_ntoa(src), pingpack->protocol,
1153 print_ipprot(pingpack->protocol));
1154 return 0;
1155 }
jjako5da68452003-01-28 16:08:47 +00001156
Harald Weltebed35df2011-11-02 13:06:18 +01001157 if (pingpack->type != 0) {
1158 if (!options.pingquiet)
1159 printf
1160 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1161 len, inet_ntoa(src), pingpack->type,
1162 print_icmptype(pingpack->type), pingpack->code);
1163 return 0;
1164 }
jjako5da68452003-01-28 16:08:47 +00001165
Harald Weltebed35df2011-11-02 13:06:18 +01001166 nreceived++;
1167 if (!options.pingquiet)
1168 printf("%d bytes from %s: icmp_seq=%d", len,
1169 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001170
Harald Weltebed35df2011-11-02 13:06:18 +01001171 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1172 gettimeofday(&tv, &tz);
1173 tp = (struct timeval *)pingpack->data;
1174 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1175 tv.tv_sec--;
1176 tv.tv_usec += 1000000;
1177 }
1178 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001179
Harald Weltebed35df2011-11-02 13:06:18 +01001180 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1181 tsum += triptime;
1182 if (triptime < tmin)
1183 tmin = triptime;
1184 if (triptime > tmax)
1185 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001186
Harald Weltebed35df2011-11-02 13:06:18 +01001187 if (!options.pingquiet)
1188 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001189
Harald Weltebed35df2011-11-02 13:06:18 +01001190 } else if (!options.pingquiet)
1191 printf("\n");
1192 return 0;
jjako5da68452003-01-28 16:08:47 +00001193}
1194
1195/* Create a new ping packet and send it off to peer. */
1196int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001197 struct in_addr *dst, int seq, unsigned int datasize)
1198{
jjako5da68452003-01-28 16:08:47 +00001199
Harald Weltebed35df2011-11-02 13:06:18 +01001200 struct ip_ping pack;
1201 uint16_t *p = (uint16_t *) & pack;
1202 uint8_t *p8 = (uint8_t *) & pack;
1203 struct in_addr src;
1204 unsigned int n;
1205 long int sum = 0;
1206 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001207
Harald Weltebed35df2011-11-02 13:06:18 +01001208 struct timezone tz;
1209 struct timeval *tp =
1210 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001211
Harald Weltebed35df2011-11-02 13:06:18 +01001212 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001213 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001214 "Ping size to large: %d!", datasize);
1215 return -1;
1216 }
jjako5da68452003-01-28 16:08:47 +00001217
Harald Weltebed35df2011-11-02 13:06:18 +01001218 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001219
Harald Weltebed35df2011-11-02 13:06:18 +01001220 pack.ipver = 0x45;
1221 pack.tos = 0x00;
1222 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1223 pack.fragid = 0x0000;
1224 pack.offset = 0x0040;
1225 pack.ttl = 0x40;
1226 pack.protocol = 0x01;
1227 pack.ipcheck = 0x0000;
1228 pack.src = src.s_addr;
1229 pack.dst = dst->s_addr;
1230 pack.type = 0x08;
1231 pack.code = 0x00;
1232 pack.checksum = 0x0000;
1233 pack.ident = 0x0000;
1234 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001235
Harald Weltebed35df2011-11-02 13:06:18 +01001236 /* Generate ICMP payload */
1237 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1238 for (n = 0; n < (datasize); n++)
1239 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001240
Harald Weltebed35df2011-11-02 13:06:18 +01001241 if (datasize >= sizeof(struct timeval))
1242 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001243
Harald Weltebed35df2011-11-02 13:06:18 +01001244 /* Calculate IP header checksum */
1245 p = (uint16_t *) & pack;
1246 count = CREATEPING_IP;
1247 sum = 0;
1248 while (count > 1) {
1249 sum += *p++;
1250 count -= 2;
1251 }
1252 while (sum >> 16)
1253 sum = (sum & 0xffff) + (sum >> 16);
1254 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001255
Harald Weltebed35df2011-11-02 13:06:18 +01001256 /* Calculate ICMP checksum */
1257 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1258 sum = 0;
1259 p = (uint16_t *) & pack;
1260 p += CREATEPING_IP / 2;
1261 while (count > 1) {
1262 sum += *p++;
1263 count -= 2;
1264 }
1265 if (count > 0)
1266 sum += *(unsigned char *)p;
1267 while (sum >> 16)
1268 sum = (sum & 0xffff) + (sum >> 16);
1269 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001270
Harald Weltebed35df2011-11-02 13:06:18 +01001271 ntransmitted++;
1272 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001273}
1274
Harald Weltebed35df2011-11-02 13:06:18 +01001275int delete_context(struct pdp_t *pdp)
1276{
1277
1278 if (tun && options.ipdown)
1279 tun_runscript(tun, options.ipdown);
1280
1281 ipdel((struct iphash_t *)pdp->peer);
1282 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1283
1284 if (1 == options.contexts)
1285 state = 5; /* Disconnected */
1286
1287 return 0;
1288}
jjakoa7cd2492003-04-11 09:40:12 +00001289
1290/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001291int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1292{
1293 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001294 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001295 struct iphdr *iph = (struct iphdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001296
Harald Welted12eab92017-08-02 19:49:47 +02001297 src.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +02001298 src.v4.s_addr = iph->saddr;
jjakoa7cd2492003-04-11 09:40:12 +00001299
Harald Weltebed35df2011-11-02 13:06:18 +01001300 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001301 printf("Dropping packet from invalid source address: %s\n",
Harald Welted12eab92017-08-02 19:49:47 +02001302 inet_ntoa(src.v4));
Harald Weltebed35df2011-11-02 13:06:18 +01001303 return 0;
1304 }
1305
1306 if (ipm->pdp) /* Check if a peer protocol is defined */
1307 gtp_data_req(gsn, ipm->pdp, pack, len);
1308 return 0;
jjako52c24142002-12-16 13:33:51 +00001309}
1310
Harald Weltebed35df2011-11-02 13:06:18 +01001311int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1312{
Harald Welted12eab92017-08-02 19:49:47 +02001313 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001314
Harald Weltebed35df2011-11-02 13:06:18 +01001315 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001316
Harald Weltebed35df2011-11-02 13:06:18 +01001317 if (cause < 0) {
1318 printf("Create PDP Context Request timed out\n");
1319 if (iph->pdp->version == 1) {
1320 printf("Retrying with version 0\n");
1321 iph->pdp->version = 0;
1322 gtp_create_context_req(gsn, iph->pdp, iph);
1323 return 0;
1324 } else {
1325 state = 0;
1326 pdp_freepdp(iph->pdp);
1327 iph->pdp = NULL;
1328 return EOF;
1329 }
1330 }
jjako2c381332003-10-21 19:09:53 +00001331
Harald Weltebed35df2011-11-02 13:06:18 +01001332 if (cause != 128) {
1333 printf
1334 ("Received create PDP context response. Cause value: %d\n",
1335 cause);
1336 state = 0;
1337 pdp_freepdp(iph->pdp);
1338 iph->pdp = NULL;
1339 return EOF; /* Not what we expected */
1340 }
jjako52c24142002-12-16 13:33:51 +00001341
Harald Weltea0d281d2017-08-02 21:48:16 +02001342 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001343 printf
1344 ("Received create PDP context response. Cause value: %d\n",
1345 cause);
1346 pdp_freepdp(iph->pdp);
1347 iph->pdp = NULL;
1348 state = 0;
1349 return EOF; /* Not a valid IP address */
1350 }
jjakoa7cd2492003-04-11 09:40:12 +00001351
Harald Weltebed35df2011-11-02 13:06:18 +01001352 printf("Received create PDP context response. IP address: %s\n",
Harald Welted12eab92017-08-02 19:49:47 +02001353 inet_ntoa(addr.v4));
jjakoa7cd2492003-04-11 09:40:12 +00001354
Harald Weltebed35df2011-11-02 13:06:18 +01001355 if ((options.createif) && (!options.net.s_addr)) {
1356 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +00001357#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +01001358 inet_aton("255.255.255.255", &m);
jjako1d3db972004-01-16 09:56:56 +00001359#else
Harald Weltebed35df2011-11-02 13:06:18 +01001360 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +00001361#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001362 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001363 tun_addaddr(tun, &addr.v4, &addr.v4, &m);
Harald Weltebed35df2011-11-02 13:06:18 +01001364 if (options.defaultroute) {
1365 struct in_addr rm;
1366 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001367 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001368 }
1369 if (options.ipup)
1370 tun_runscript(tun, options.ipup);
1371 }
jjako52c24142002-12-16 13:33:51 +00001372
Harald Weltebed35df2011-11-02 13:06:18 +01001373 ipset((struct iphash_t *)pdp->peer, &addr);
1374
1375 state = 2; /* Connected */
1376
1377 return 0;
jjako52c24142002-12-16 13:33:51 +00001378}
1379
Harald Weltebed35df2011-11-02 13:06:18 +01001380int delete_pdp_conf(struct pdp_t *pdp, int cause)
1381{
1382 printf("Received delete PDP context response. Cause value: %d\n",
1383 cause);
1384 return 0;
jjako52c24142002-12-16 13:33:51 +00001385}
1386
Harald Weltebed35df2011-11-02 13:06:18 +01001387int echo_conf(int recovery)
1388{
jjako91aaf222003-10-22 10:09:32 +00001389
Harald Weltebed35df2011-11-02 13:06:18 +01001390 if (recovery < 0) {
1391 printf("Echo Request timed out\n");
1392 if (echoversion == 1) {
1393 printf("Retrying with version 0\n");
1394 echoversion = 0;
1395 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1396 return 0;
1397 } else {
1398 state = 0;
1399 return EOF;
1400 }
1401 } else {
1402 printf("Received echo response\n");
1403 if (!options.contexts)
1404 state = 5;
1405 }
1406 return 0;
jjako52c24142002-12-16 13:33:51 +00001407}
1408
Harald Weltebed35df2011-11-02 13:06:18 +01001409int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1410{
1411 /* if (cause < 0) return 0; Some error occurred. We don't care */
1412 switch (type) {
1413 case GTP_ECHO_REQ:
1414 return echo_conf(cause);
1415 case GTP_CREATE_PDP_REQ:
1416 return create_pdp_conf(pdp, cbp, cause);
1417 case GTP_DELETE_PDP_REQ:
1418 if (cause != 128)
1419 return 0; /* Request not accepted. We don't care */
1420 return delete_pdp_conf(pdp, cause);
1421 default:
1422 return 0;
1423 }
jjako52c24142002-12-16 13:33:51 +00001424}
1425
Harald Weltebed35df2011-11-02 13:06:18 +01001426int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1427{
1428 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1429 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001430}
1431
1432int main(int argc, char **argv)
1433{
Harald Weltebed35df2011-11-02 13:06:18 +01001434 fd_set fds; /* For select() */
1435 struct timeval idleTime; /* How long to select() */
1436 struct pdp_t *pdp;
1437 int n;
1438 int starttime = time(NULL); /* Time program was started */
1439 int stoptime = 0; /* Time to exit */
1440 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001441 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001442
Harald Weltebed35df2011-11-02 13:06:18 +01001443 struct timezone tz; /* Used for calculating ping times */
1444 struct timeval tv;
1445 int diff;
jjako52c24142002-12-16 13:33:51 +00001446
bjovana8f71eb2017-02-24 17:39:20 +01001447 signal(SIGTERM, signal_handler);
1448 signal(SIGHUP, signal_handler);
1449 signal(SIGINT, signal_handler);
1450
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001451 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001452
Harald Weltebed35df2011-11-02 13:06:18 +01001453 /* Process options given in configuration file and command line */
1454 if (process_options(argc, argv))
1455 exit(1);
jjako52c24142002-12-16 13:33:51 +00001456
Harald Weltebed35df2011-11-02 13:06:18 +01001457 printf("\nInitialising GTP library\n");
1458 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001459 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001460 exit(1);
1461 }
1462 if (gsn->fd0 > maxfd)
1463 maxfd = gsn->fd0;
1464 if (gsn->fd1c > maxfd)
1465 maxfd = gsn->fd1c;
1466 if (gsn->fd1u > maxfd)
1467 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001468
Harald Weltebed35df2011-11-02 13:06:18 +01001469 gtp_set_cb_delete_context(gsn, delete_context);
1470 gtp_set_cb_conf(gsn, conf);
1471 if (options.createif)
1472 gtp_set_cb_data_ind(gsn, encaps_tun);
1473 else
1474 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001475
Harald Weltebed35df2011-11-02 13:06:18 +01001476 if (options.createif) {
1477 printf("Setting up interface\n");
1478 /* Create a tunnel interface */
Harald Weltedda21ed2017-08-12 15:07:02 +02001479 if (tun_new((struct tun_t **)&tun, NULL)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001480 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001481 "Failed to create tun");
1482 exit(1);
1483 }
1484 tun_set_cb_ind(tun, cb_tun_ind);
1485 if (tun->fd > maxfd)
1486 maxfd = tun->fd;
1487 }
jjakoa7cd2492003-04-11 09:40:12 +00001488
Harald Weltebed35df2011-11-02 13:06:18 +01001489 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001490 struct in_addr mask;
1491 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001492 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001493 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001494 if (options.defaultroute) {
1495 struct in_addr rm;
1496 rm.s_addr = 0;
1497 tun_addroute(tun, &rm, &options.destaddr, &rm);
1498 }
1499 if (options.ipup)
1500 tun_runscript(tun, options.ipup);
1501 }
jjakoa7cd2492003-04-11 09:40:12 +00001502
Harald Weltebed35df2011-11-02 13:06:18 +01001503 /* Initialise hash tables */
1504 memset(&iphash, 0, sizeof(iphash));
1505 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001506
Harald Weltebed35df2011-11-02 13:06:18 +01001507 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001508
Harald Weltebed35df2011-11-02 13:06:18 +01001509 /* See if anybody is there */
1510 printf("Sending off echo request\n");
1511 echoversion = options.gtpversion;
1512 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001513
Harald Weltebed35df2011-11-02 13:06:18 +01001514 for (n = 0; n < options.contexts; n++) {
1515 uint64_t myimsi;
1516 printf("Setting up PDP context #%d\n", n);
1517 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001518
Harald Weltebed35df2011-11-02 13:06:18 +01001519 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001520
Harald Weltebed35df2011-11-02 13:06:18 +01001521 /* Allocated here. */
1522 /* If create context failes we have to deallocate ourselves. */
1523 /* Otherwise it is deallocated by gtplib */
1524 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001525
Harald Weltebed35df2011-11-02 13:06:18 +01001526 pdp->peer = &iparr[n];
1527 pdp->ipif = tun; /* TODO */
1528 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001529
Harald Weltebed35df2011-11-02 13:06:18 +01001530 if (options.gtpversion == 0) {
1531 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001532 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001533 "QoS length too big");
1534 exit(1);
1535 } else {
1536 memcpy(pdp->qos_req0, options.qos.v,
1537 options.qos.l);
1538 }
1539 }
jjakoa7cd2492003-04-11 09:40:12 +00001540
Harald Weltebed35df2011-11-02 13:06:18 +01001541 pdp->qos_req.l = options.qos.l;
1542 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001543
Harald Weltebed35df2011-11-02 13:06:18 +01001544 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001545
Harald Weltebed35df2011-11-02 13:06:18 +01001546 pdp->rattype.l = options.rattype.l;
1547 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1548 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001549
Harald Weltebed35df2011-11-02 13:06:18 +01001550 pdp->userloc.l = options.userloc.l;
1551 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1552 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001553
Harald Weltebed35df2011-11-02 13:06:18 +01001554 pdp->rai.l = options.rai.l;
1555 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1556 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001557
Harald Weltebed35df2011-11-02 13:06:18 +01001558 pdp->mstz.l = options.mstz.l;
1559 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1560 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001561
Harald Weltebed35df2011-11-02 13:06:18 +01001562 pdp->imeisv.l = options.imeisv.l;
1563 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1564 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001565
Harald Weltebed35df2011-11-02 13:06:18 +01001566 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001567
Harald Weltebed35df2011-11-02 13:06:18 +01001568 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001569 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001570 "APN length too big");
1571 exit(1);
1572 } else {
1573 pdp->apn_use.l = options.apn.l;
1574 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1575 }
jjako193e8b12003-11-10 12:31:41 +00001576
Harald Weltebed35df2011-11-02 13:06:18 +01001577 pdp->gsnlc.l = sizeof(options.listen);
1578 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1579 pdp->gsnlu.l = sizeof(options.listen);
1580 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001581
Harald Weltebed35df2011-11-02 13:06:18 +01001582 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001583 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001584 "MSISDN length too big");
1585 exit(1);
1586 } else {
1587 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1588 }
jjakob62c3dd2004-05-27 18:51:55 +00001589
Harald Welte840a8e92017-09-24 18:12:40 +08001590 /* Request dynamic IP address */
1591 pdp->eua.v[0] = PDP_EUA_ORG_IETF;
1592 pdp->eua.v[1] = options.pdp_type;
1593 pdp->eua.l = 2;
jjako52c24142002-12-16 13:33:51 +00001594
Harald Weltebed35df2011-11-02 13:06:18 +01001595 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001596 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001597 "PCO length too big");
1598 exit(1);
1599 } else {
1600 pdp->pco_req.l = options.pco.l;
1601 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1602 }
jjako52c24142002-12-16 13:33:51 +00001603
Harald Weltebed35df2011-11-02 13:06:18 +01001604 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001605
Harald Weltebed35df2011-11-02 13:06:18 +01001606 pdp->hisaddr0 = options.remote;
1607 pdp->hisaddr1 = options.remote;
1608
1609 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1610 512 = Flat rate, 256 = Hot billing */
1611
Harald Weltefbb9c7f2017-09-24 11:50:20 +08001612 pdp->tx_gpdu_seq = options.tx_gpdu_seq;
1613
Harald Weltebed35df2011-11-02 13:06:18 +01001614 /* Create context */
1615 /* We send this of once. Retransmissions are handled by gtplib */
1616 gtp_create_context_req(gsn, pdp, &iparr[n]);
1617 }
1618
1619 state = 1; /* Enter wait_connection state */
1620
1621 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001622
jjako52c24142002-12-16 13:33:51 +00001623 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001624 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001625 /******************************************************************/
1626
Harald Weltebed35df2011-11-02 13:06:18 +01001627 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001628
Harald Weltebed35df2011-11-02 13:06:18 +01001629 /* Take down client after timeout after disconnect */
1630 if ((4 == state) && ((stoptime) <= time(NULL))) {
1631 state = 5;
1632 }
jjako7b8fad42003-07-07 14:37:42 +00001633
Harald Weltebed35df2011-11-02 13:06:18 +01001634 /* Take down client after timelimit timeout */
1635 if ((2 == state) && (options.timelimit) &&
1636 ((starttime + options.timelimit) <= time(NULL))) {
1637 state = 3;
1638 }
jjako7b8fad42003-07-07 14:37:42 +00001639
Harald Weltebed35df2011-11-02 13:06:18 +01001640 /* Take down client after ping timeout */
1641 if ((2 == state) && (pingtimeout)
1642 && (pingtimeout <= time(NULL))) {
1643 state = 3;
1644 }
jjako7b8fad42003-07-07 14:37:42 +00001645
Harald Weltebed35df2011-11-02 13:06:18 +01001646 /* Set pingtimeout for later disconnection */
1647 if (options.pingcount && ntransmitted >= options.pingcount) {
1648 pingtimeout = time(NULL) + 5; /* Extra seconds */
1649 }
jjako7b8fad42003-07-07 14:37:42 +00001650
Harald Weltebed35df2011-11-02 13:06:18 +01001651 /* Print statistics if no more ping packets are missing */
1652 if (ntransmitted && options.pingcount
1653 && nreceived >= options.pingcount) {
1654 ping_finish();
1655 if (!options.createif)
1656 state = 3;
1657 }
jjako7b8fad42003-07-07 14:37:42 +00001658
Harald Weltebed35df2011-11-02 13:06:18 +01001659 /* Send off disconnect */
1660 if (3 == state) {
1661 state = 4;
1662 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1663 for (n = 0; n < options.contexts; n++) {
1664 /* Delete context */
1665 printf("Disconnecting PDP context #%d\n", n);
1666 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1667 1);
1668 if ((options.pinghost.s_addr != 0)
1669 && ntransmitted)
1670 ping_finish();
1671 }
1672 }
jjako7b8fad42003-07-07 14:37:42 +00001673
Harald Weltebed35df2011-11-02 13:06:18 +01001674 /* Send of ping packets */
1675 diff = 0;
1676 while ((diff <= 0) &&
1677 /* Send off an ICMP ping packet */
1678 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1679 ((pingseq < options.pingcount)
1680 || (options.pingcount == 0))) {
1681 if (!pingseq)
1682 gettimeofday(&firstping, &tz); /* Set time of first ping */
1683 gettimeofday(&tv, &tz);
1684 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1685 if (diff <= 0) {
1686 if (options.debug)
1687 printf("Create_ping %d\n", diff);
1688 create_ping(gsn,
1689 iparr[pingseq %
1690 options.contexts].pdp,
1691 &options.pinghost, pingseq,
1692 options.pingsize);
1693 pingseq++;
1694 }
1695 }
jjako5da68452003-01-28 16:08:47 +00001696
Harald Weltebed35df2011-11-02 13:06:18 +01001697 FD_ZERO(&fds);
1698 if (tun)
1699 FD_SET(tun->fd, &fds);
1700 FD_SET(gsn->fd0, &fds);
1701 FD_SET(gsn->fd1c, &fds);
1702 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001703
Harald Weltebed35df2011-11-02 13:06:18 +01001704 gtp_retranstimeout(gsn, &idleTime);
1705 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001706
Harald Weltebed35df2011-11-02 13:06:18 +01001707 if (options.debug)
1708 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1709 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001710
bjovana8f71eb2017-02-24 17:39:20 +01001711 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001712 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1713 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001714 if (errno == EINTR)
1715 signal_received = 1;
1716 else
1717 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1718 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001719 break;
1720 case 0:
1721 gtp_retrans(gsn); /* Only retransmit if nothing else */
1722 break;
1723 default:
1724 break;
1725 }
1726
bjovana8f71eb2017-02-24 17:39:20 +01001727 if (!signal_received) {
1728
1729 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1730 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1731 "TUN decaps failed");
1732 }
1733
1734 if (FD_ISSET(gsn->fd0, &fds))
1735 gtp_decaps0(gsn);
1736
1737 if (FD_ISSET(gsn->fd1c, &fds))
1738 gtp_decaps1c(gsn);
1739
1740 if (FD_ISSET(gsn->fd1u, &fds))
1741 gtp_decaps1u(gsn);
1742
Harald Weltebed35df2011-11-02 13:06:18 +01001743 }
Harald Weltebed35df2011-11-02 13:06:18 +01001744 }
1745
1746 gtp_free(gsn); /* Clean up the gsn instance */
1747
1748 if (options.createif)
1749 tun_free(tun);
1750
1751 if (0 == state)
1752 exit(1); /* Indicate error */
1753
1754 return 0;
jjako52c24142002-12-16 13:33:51 +00001755}