blob: 1f0b3f9b037b5c1ed46e6b274485c059a7e5392d [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
jjako52c24142002-12-16 13:33:51 +00004 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/*
13 * sgsnemu.c
14 *
15 */
16
jjako52c24142002-12-16 13:33:51 +000017#ifdef __linux__
Harald Weltebed35df2011-11-02 13:06:18 +010018#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000019#endif
20
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010021#include <osmocom/core/application.h>
22
jjako52c24142002-12-16 13:33:51 +000023#include <ctype.h>
24#include <netdb.h>
25#include <signal.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <netinet/in.h>
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;
jjakoa7cd2492003-04-11 09:40:12 +0000120} options;
jjako52c24142002-12-16 13:33:51 +0000121
jjako5da68452003-01-28 16:08:47 +0000122/* Definitions to use for PING. Most of the ping code was derived from */
123/* the original ping program by Mike Muuss */
124
125/* IP header and ICMP echo header */
126#define CREATEPING_MAX 2048
127#define CREATEPING_IP 20
128#define CREATEPING_ICMP 8
129
130struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100131 uint8_t ipver; /* Type and header length */
132 uint8_t tos; /* Type of Service */
133 uint16_t length; /* Total length */
134 uint16_t fragid; /* Identifier */
135 uint16_t offset; /* Flags and fragment offset */
136 uint8_t ttl; /* Time to live */
137 uint8_t protocol; /* Protocol */
138 uint16_t ipcheck; /* Header checksum */
139 uint32_t src; /* Source address */
140 uint32_t dst; /* Destination */
141 uint8_t type; /* Type and header length */
142 uint8_t code; /* Code */
143 uint16_t checksum; /* Header checksum */
144 uint16_t ident; /* Identifier */
145 uint16_t seq; /* Sequence number */
146 uint8_t data[CREATEPING_MAX]; /* Data */
147} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000148
149/* Statistical values for ping */
150int nreceived = 0;
151int ntreceived = 0;
152int ntransmitted = 0;
153int tmin = 999999999;
154int tmax = 0;
155int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100156int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000157struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000158
bjovana8f71eb2017-02-24 17:39:20 +0100159void signal_handler(int signo)
160{
161 if (state == 2)
162 state = 3; /* Tell main loop to finish. */
163}
164
Harald Welted12eab92017-08-02 19:49:47 +0200165int ipset(struct iphash_t *ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100166{
Harald Welted12eab92017-08-02 19:49:47 +0200167 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100168 struct iphash_t *h;
169 struct iphash_t *prev = NULL;
170 ipaddr->ipnext = NULL;
Harald Welted12eab92017-08-02 19:49:47 +0200171 ipaddr->addr = *addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100172 for (h = iphash[hash]; h; h = h->ipnext)
173 prev = h;
174 if (!prev)
175 iphash[hash] = ipaddr;
176 else
177 prev->ipnext = ipaddr;
178 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000179}
180
Harald Weltebed35df2011-11-02 13:06:18 +0100181int ipdel(struct iphash_t *ipaddr)
182{
Harald Welted12eab92017-08-02 19:49:47 +0200183 int hash = ippool_hash(&ipaddr->addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100184 struct iphash_t *h;
185 struct iphash_t *prev = NULL;
186 for (h = iphash[hash]; h; h = h->ipnext) {
187 if (h == ipaddr) {
188 if (!prev)
189 iphash[hash] = h->ipnext;
190 else
191 prev->ipnext = h->ipnext;
192 return 0;
193 }
194 prev = h;
195 }
196 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000197}
198
Harald Welted12eab92017-08-02 19:49:47 +0200199int ipget(struct iphash_t **ipaddr, struct in46_addr *addr)
Harald Weltebed35df2011-11-02 13:06:18 +0100200{
Harald Welted12eab92017-08-02 19:49:47 +0200201 int hash = ippool_hash(addr) % MAXCONTEXTS;
Harald Weltebed35df2011-11-02 13:06:18 +0100202 struct iphash_t *h;
203 for (h = iphash[hash]; h; h = h->ipnext) {
Harald Welted12eab92017-08-02 19:49:47 +0200204 if (in46a_equal(&h->addr, addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +0100205 *ipaddr = h;
206 return 0;
207 }
208 }
209 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000210}
211
jjakoa7cd2492003-04-11 09:40:12 +0000212/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +0100213void log_pid(char *pidfile)
214{
215 FILE *file;
216 mode_t oldmask;
217
218 oldmask = umask(022);
219 file = fopen(pidfile, "w");
220 umask(oldmask);
221 if (!file)
222 return;
223 fprintf(file, "%d\n", (int)getpid());
224 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000225}
226
Harald Weltebed35df2011-11-02 13:06:18 +0100227int process_options(int argc, char **argv)
228{
229 /* gengeopt declarations */
230 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000231
Harald Weltebed35df2011-11-02 13:06:18 +0100232 struct hostent *host;
233 unsigned int n;
234 uint16_t i;
235 uint8_t a;
236 uint8_t b;
237 char *tmp;
238 char *pch;
239 char *type;
240 char *mcc;
241 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100242 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100243 char *lac;
244 int lac_d;
245 char *rest;
246 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
247 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
248 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
249 int sign;
250 int nbquarters;
251 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000252
Harald Weltebed35df2011-11-02 13:06:18 +0100253 if (cmdline_parser(argc, argv, &args_info) != 0)
254 return -1;
255 if (args_info.debug_flag) {
256 if (args_info.remote_arg)
257 printf("remote: %s\n", args_info.remote_arg);
258 if (args_info.listen_arg)
259 printf("listen: %s\n", args_info.listen_arg);
260 if (args_info.conf_arg)
261 printf("conf: %s\n", args_info.conf_arg);
262 printf("debug: %d\n", args_info.debug_flag);
263 if (args_info.imsi_arg)
264 printf("imsi: %s\n", args_info.imsi_arg);
265 printf("qos: %#08x\n", args_info.qos_arg);
266 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
267 printf("qose2: %#04x\n", args_info.qose2_arg);
268 printf("qose3: %#06x\n", args_info.qose3_arg);
269 printf("qose4: %#06x\n", args_info.qose4_arg);
270 printf("charging: %#04x\n", args_info.charging_arg);
271 if (args_info.apn_arg)
272 printf("apn: %s\n", args_info.apn_arg);
273 if (args_info.msisdn_arg)
274 printf("msisdn: %s\n", args_info.msisdn_arg);
275 if (args_info.uid_arg)
276 printf("uid: %s\n", args_info.uid_arg);
277 if (args_info.pwd_arg)
278 printf("pwd: %s\n", args_info.pwd_arg);
279 if (args_info.pidfile_arg)
280 printf("pidfile: %s\n", args_info.pidfile_arg);
281 if (args_info.statedir_arg)
282 printf("statedir: %s\n", args_info.statedir_arg);
283 if (args_info.dns_arg)
284 printf("dns: %s\n", args_info.dns_arg);
285 printf("contexts: %d\n", args_info.contexts_arg);
286 printf("timelimit: %d\n", args_info.timelimit_arg);
287 printf("createif: %d\n", args_info.createif_flag);
288 if (args_info.ipup_arg)
289 printf("ipup: %s\n", args_info.ipup_arg);
290 if (args_info.ipdown_arg)
291 printf("ipdown: %s\n", args_info.ipdown_arg);
292 printf("defaultroute: %d\n", args_info.defaultroute_flag);
293 if (args_info.pinghost_arg)
294 printf("pinghost: %s\n", args_info.pinghost_arg);
295 printf("pingrate: %d\n", args_info.pingrate_arg);
296 printf("pingsize: %d\n", args_info.pingsize_arg);
297 printf("pingcount: %d\n", args_info.pingcount_arg);
298 printf("pingquiet: %d\n", args_info.pingquiet_flag);
299 printf("norecovery: %d\n", args_info.norecovery_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100300 }
jjakoa7cd2492003-04-11 09:40:12 +0000301
Harald Weltebed35df2011-11-02 13:06:18 +0100302 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000303
Harald Weltebed35df2011-11-02 13:06:18 +0100304 if (args_info.conf_arg) {
305 if (cmdline_parser_configfile
306 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
307 return -1;
308 if (args_info.debug_flag) {
309 printf("cmdline_parser_configfile\n");
310 if (args_info.remote_arg)
311 printf("remote: %s\n", args_info.remote_arg);
312 if (args_info.listen_arg)
313 printf("listen: %s\n", args_info.listen_arg);
314 if (args_info.conf_arg)
315 printf("conf: %s\n", args_info.conf_arg);
316 printf("debug: %d\n", args_info.debug_flag);
317 if (args_info.imsi_arg)
318 printf("imsi: %s\n", args_info.imsi_arg);
319 printf("qos: %#08x\n", args_info.qos_arg);
320 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
321 printf("qose2: %#04x\n", args_info.qose2_arg);
322 printf("qose3: %#06x\n", args_info.qose3_arg);
323 printf("qose4: %#06x\n", args_info.qose4_arg);
324 printf("charging: %#04x\n", args_info.charging_arg);
325 if (args_info.apn_arg)
326 printf("apn: %s\n", args_info.apn_arg);
327 if (args_info.msisdn_arg)
328 printf("msisdn: %s\n", args_info.msisdn_arg);
329 if (args_info.uid_arg)
330 printf("uid: %s\n", args_info.uid_arg);
331 if (args_info.pwd_arg)
332 printf("pwd: %s\n", args_info.pwd_arg);
333 if (args_info.pidfile_arg)
334 printf("pidfile: %s\n", args_info.pidfile_arg);
335 if (args_info.statedir_arg)
336 printf("statedir: %s\n",
337 args_info.statedir_arg);
338 if (args_info.dns_arg)
339 printf("dns: %s\n", args_info.dns_arg);
340 printf("contexts: %d\n", args_info.contexts_arg);
341 printf("timelimit: %d\n", args_info.timelimit_arg);
342 printf("createif: %d\n", args_info.createif_flag);
343 if (args_info.ipup_arg)
344 printf("ipup: %s\n", args_info.ipup_arg);
345 if (args_info.ipdown_arg)
346 printf("ipdown: %s\n", args_info.ipdown_arg);
347 printf("defaultroute: %d\n",
348 args_info.defaultroute_flag);
349 if (args_info.pinghost_arg)
350 printf("pinghost: %s\n",
351 args_info.pinghost_arg);
352 printf("pingrate: %d\n", args_info.pingrate_arg);
353 printf("pingsize: %d\n", args_info.pingsize_arg);
354 printf("pingcount: %d\n", args_info.pingcount_arg);
355 printf("pingquiet: %d\n", args_info.pingquiet_flag);
356 printf("norecovery: %d\n", args_info.norecovery_flag);
357 }
358 }
jjako193e8b12003-11-10 12:31:41 +0000359
Harald Weltebed35df2011-11-02 13:06:18 +0100360 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000361
Harald Weltebed35df2011-11-02 13:06:18 +0100362 /* foreground */
363 /* If fg flag not given run as a daemon */
364 /* Do not allow sgsnemu to run as deamon
365 if (!args_info.fg_flag)
366 {
367 closelog();
368 freopen("/dev/null", "w", stdout);
369 freopen("/dev/null", "w", stderr);
370 freopen("/dev/null", "r", stdin);
371 daemon(0, 0);
372 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
373 } */
jjako1a51df72004-07-20 08:30:21 +0000374
Harald Weltebed35df2011-11-02 13:06:18 +0100375 /* debug */
376 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000377
Harald Weltebed35df2011-11-02 13:06:18 +0100378 /* pidfile */
379 /* This has to be done after we have our final pid */
380 if (args_info.pidfile_arg) {
381 log_pid(args_info.pidfile_arg);
382 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200383
Harald Weltebed35df2011-11-02 13:06:18 +0100384 /* dns */
385 /* If no dns option is given use system default */
386 /* Do hostname lookup to translate hostname to IP address */
387 printf("\n");
388 if (args_info.dns_arg) {
389 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100390 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100391 "Invalid DNS address: %s!", args_info.dns_arg);
392 return -1;
393 } else {
394 memcpy(&options.dns.s_addr, host->h_addr,
395 host->h_length);
396 _res.nscount = 1;
397 _res.nsaddr_list[0].sin_addr = options.dns;
398 printf("Using DNS server: %s (%s)\n",
399 args_info.dns_arg, inet_ntoa(options.dns));
400 }
401 } else {
402 options.dns.s_addr = 0;
403 printf("Using default DNS server\n");
404 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200405
Harald Weltebed35df2011-11-02 13:06:18 +0100406 /* listen */
407 /* If no listen option is specified listen to any local port */
408 /* Do hostname lookup to translate hostname to IP address */
409 if (args_info.listen_arg) {
410 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100411 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100412 "Invalid listening address: %s!",
413 args_info.listen_arg);
414 return -1;
415 } else {
416 memcpy(&options.listen.s_addr, host->h_addr,
417 host->h_length);
418 printf("Local IP address is: %s (%s)\n",
419 args_info.listen_arg, inet_ntoa(options.listen));
420 }
421 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100422 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100423 "Listening address must be specified: %s!",
424 args_info.listen_arg);
425 return -1;
426 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200427
Harald Weltebed35df2011-11-02 13:06:18 +0100428 /* remote */
429 /* If no remote option is specified terminate */
430 /* Do hostname lookup to translate hostname to IP address */
431 if (args_info.remote_arg) {
432 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100433 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100434 "Invalid remote address: %s!",
435 args_info.remote_arg);
436 return -1;
437 } else {
438 memcpy(&options.remote.s_addr, host->h_addr,
439 host->h_length);
440 printf("Remote IP address is: %s (%s)\n",
441 args_info.remote_arg, inet_ntoa(options.remote));
442 }
443 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100444 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100445 "No remote address given!");
446 return -1;
447 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200448
Harald Weltebed35df2011-11-02 13:06:18 +0100449 /* imsi */
450 if (strlen(args_info.imsi_arg) != 15) {
451 printf("Invalid IMSI\n");
452 return -1;
453 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200454
Harald Weltebed35df2011-11-02 13:06:18 +0100455 options.imsi = 0xf000000000000000ull;
456 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
457 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
458 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
459 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
460 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
461 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
462 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
463 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
464 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
465 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
466 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
467 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
468 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
469 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
470 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200471
Harald Weltebed35df2011-11-02 13:06:18 +0100472 printf("IMSI is: %s (%#08llx)\n",
473 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200474
Harald Weltebed35df2011-11-02 13:06:18 +0100475 /* nsapi */
476 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
477 printf("Invalid NSAPI\n");
478 return -1;
479 }
480 options.nsapi = args_info.nsapi_arg;
481 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200482
Harald Weltebed35df2011-11-02 13:06:18 +0100483 /* qos */
484 options.qos.l = 4;
485 options.qos.v[3] = (args_info.qos_arg) & 0xff;
486 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
487 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
488 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
489 /* Extensions according to 3GPP TS 24.008 */
490 if (args_info.qose1_given == 1) {
491 options.qos.l = 12;
492 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
493 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
494 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
495 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
496 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
497 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
498 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
499 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
500 if (args_info.qose2_given == 1) {
501 options.qos.l = 13;
502 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
503 if (args_info.qose3_given == 1) {
504 options.qos.l = 15;
505 options.qos.v[14] =
506 (args_info.qose3_arg) & 0xff;
507 options.qos.v[13] =
508 ((args_info.qose3_arg) >> 8) & 0xff;
509 if (args_info.qose4_given == 1) {
510 options.qos.l = 17;
511 options.qos.v[16] =
512 (args_info.qose4_arg) & 0xff;
513 options.qos.v[15] =
514 ((args_info.qose4_arg) >> 8) & 0xff;
515 }
516 }
517 }
518 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200519
Harald Weltebed35df2011-11-02 13:06:18 +0100520 /* charging */
521 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200522
Harald Weltebed35df2011-11-02 13:06:18 +0100523 /* contexts */
524 if (args_info.contexts_arg > MAXCONTEXTS) {
525 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
526 return -1;
527 }
528 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200529
Harald Weltebed35df2011-11-02 13:06:18 +0100530 /* Timelimit */
531 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200532
Harald Weltebed35df2011-11-02 13:06:18 +0100533 /* gtpversion */
534 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
535 printf("Invalid GTP version\n");
536 return -1;
537 }
538 options.gtpversion = args_info.gtpversion_arg;
539 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200540
Harald Weltebed35df2011-11-02 13:06:18 +0100541 /* apn */
542 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
543 printf("Invalid APN\n");
544 return -1;
545 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100546 options.apn.l = strlen(args_info.apn_arg) + 1;
547
548 apn = (char *)options.apn.v;
549 for (tok = strtok(args_info.apn_arg, ".");
550 tok != NULL;
551 tok = strtok(NULL, ".")) {
552 size_t len = strlen(tok);
553
554 *apn++ = (char)len;
555 strncpy(apn, tok, len);
556 apn += len;
557 }
558
Harald Weltebed35df2011-11-02 13:06:18 +0100559 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200560
Harald Weltebed35df2011-11-02 13:06:18 +0100561 /* selmode */
562 options.selmode = args_info.selmode_arg;
563 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200564
Harald Weltebed35df2011-11-02 13:06:18 +0100565 /* rattype */
566 if (args_info.rattype_given == 1) {
567 options.rattype_given = 1;
568 options.rattype.l = strlen(args_info.rattype_arg);
569 options.rattype.v[0] = atoi(args_info.rattype_arg);
570 printf("Using RAT Type: %s\n", args_info.rattype_arg);
571 }
Harald Welte41af5692011-10-07 18:42:34 +0200572
Harald Weltebed35df2011-11-02 13:06:18 +0100573 /* userloc */
574 if (args_info.userloc_given == 1) {
575 printf("Using User Location Information: %s\n",
576 args_info.userloc_arg);
577 tmp = args_info.userloc_arg;
578 n = 0;
579 pch = strtok(tmp, ".");
580 while (pch != NULL) {
581 userloc_el[n] = pch;
582 pch = strtok(NULL, ".");
583 n++;
584 }
Harald Welte41af5692011-10-07 18:42:34 +0200585
Harald Weltebed35df2011-11-02 13:06:18 +0100586 options.userloc_given = 1;
587 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200588
Harald Weltebed35df2011-11-02 13:06:18 +0100589 /* 3GPP Geographic Location Type t0 / t1 / t2 */
590 type = userloc_el[0];
591 printf("->type : %c\n", type[0]);
592 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
593 printf("Invalid type \n");
594 return -1;
595 }
596 /* options.userloc.v[0] = 0x00 */
597 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200598
Harald Weltebed35df2011-11-02 13:06:18 +0100599 /* MCC */
600 mcc = userloc_el[1];
601 printf("->mcc : %s\n", mcc);
602 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200603 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100604 return -1;
605 }
Harald Welte41af5692011-10-07 18:42:34 +0200606
Harald Weltebed35df2011-11-02 13:06:18 +0100607 /* MNC */
608 mnc = userloc_el[2];
609 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200610
Harald Weltebed35df2011-11-02 13:06:18 +0100611 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
612 /* options.userloc.v[1] = 0x52 */
613 a = (uint8_t) (mcc[0] - 48);
614 b = (uint8_t) (mcc[1] - 48);
615 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200616
Harald Weltebed35df2011-11-02 13:06:18 +0100617 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
618 /* options.userloc.v[2] = 0xf0 */
619 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200620
Harald Weltebed35df2011-11-02 13:06:18 +0100621 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200622 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100623 return -1;
624 }
625 if (strlen(mnc) == 2) {
626 b = 15;
627 }
628 if (strlen(mnc) == 3) {
629 b = (uint8_t) (mnc[2] - 48);
630 }
631 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200632
Harald Weltebed35df2011-11-02 13:06:18 +0100633 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
634 /* options.userloc.v[3] = 0x99 */
635 a = (uint8_t) (mnc[0] - 48);
636 b = (uint8_t) (mnc[1] - 48);
637 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200638
Harald Weltebed35df2011-11-02 13:06:18 +0100639 /* LAC */
640 lac = userloc_el[3];
641 /*options.userloc.v[4] = 0x12 ; */
642 /*options.userloc.v[5] = 0x10 ; */
643 printf("->LAC: %s\n", lac);
644 lac_d = atoi(lac);
645 if (lac_d > 65535 || lac_d < 1) {
646 printf("Invalid LAC\n");
647 return -1;
648 }
649 i = lac_d >> 8;
650 options.userloc.v[4] = i; /* octet 8 - LAC */
651 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200652
Harald Weltebed35df2011-11-02 13:06:18 +0100653 /* CI/SAC/RAC */
654 rest = userloc_el[4];
655 printf("->CI/SAC/RAC : %s\n", rest);
656 lac_d = atoi(rest);
657 if (lac_d > 65535 || lac_d < 1) {
658 printf("Invalid CI/SAC/RAC\n");
659 return -1;
660 }
661 /*options.userloc.v[6] = 0x04 ; */
662 /*options.userloc.v[7] = 0xb7 ; */
663 i = lac_d >> 8;
664 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
665 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
666 }
jjakoa7cd2492003-04-11 09:40:12 +0000667
Harald Weltebed35df2011-11-02 13:06:18 +0100668 /* RAI */
669 if (args_info.rai_given == 1) {
670 printf("Using RAI: %s\n", args_info.rai_arg);
671 tmp = args_info.rai_arg;
672 n = 0;
673 pch = strtok(tmp, ".");
674 while (pch != NULL) {
675 rai_el[n] = pch;
676 pch = strtok(NULL, ".");
677 n++;
678 }
jjakoa7cd2492003-04-11 09:40:12 +0000679
Harald Weltebed35df2011-11-02 13:06:18 +0100680 options.rai_given = 1;
681 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000682
Harald Weltebed35df2011-11-02 13:06:18 +0100683 /* MCC */
684 mcc = rai_el[0];
685 printf("->mcc : %s\n", mcc);
686 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200687 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100688 return -1;
689 }
690
691 /* MNC */
692 mnc = rai_el[1];
693 printf("->mnc : %s\n", mnc);
694
695 a = (uint8_t) (mcc[0] - 48);
696 b = (uint8_t) (mcc[1] - 48);
697 options.rai.v[0] = 16 * b + a;
698
699 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
700 a = (uint8_t) (mcc[2] - 48);
701
702 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200703 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100704 return -1;
705 }
706 if (strlen(mnc) == 2) {
707 b = 15;
708 }
709 if (strlen(mnc) == 3) {
710 b = (uint8_t) (mnc[2] - 48);
711 }
712 options.rai.v[1] = 16 * b + a;
713
714 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
715 a = (uint8_t) (mnc[0] - 48);
716 b = (uint8_t) (mnc[1] - 48);
717 options.rai.v[2] = 16 * b + a;
718
719 /* LAC */
720 lac = rai_el[2];
721 printf("->LAC: %s\n", lac);
722 lac_d = atoi(lac);
723 if (lac_d > 65535 || lac_d < 1) {
724 printf("Invalid LAC\n");
725 return -1;
726 }
727 i = lac_d >> 8;
728 options.rai.v[3] = i; /* octet 5 - LAC */
729 options.rai.v[4] = lac_d; /* octet 6 - LAC */
730
731 /* RAC */
732 rest = rai_el[3];
733 printf("->RAC : %s\n", rest);
734 lac_d = atoi(rest);
735 if (lac_d > 255 || lac_d < 1) {
736 printf("Invalid RAC\n");
737 return -1;
738 }
739 options.rai.v[5] = lac_d; /* octet 7 - RAC */
740 }
741
742 /* mstz */
743 if (args_info.mstz_given == 1) {
744 options.mstz_given = 1;
745 options.mstz.l = 2;
746
747 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
748 tmp = args_info.mstz_arg;
749 n = 0;
750 pch = strtok(tmp, ".");
751 while (pch != NULL) {
752 mstz_el[n] = pch;
753 pch = strtok(NULL, ".");
754 n++;
755 }
756
757 /* sign */
758 sign = atoi(mstz_el[0]);
759 printf("->Sign (0=+ / 1=-): %d\n", sign);
760 if (sign != 0 && sign != 1) {
761 printf("Invalid Sign \n");
762 return -1;
763 }
764 /* nbquarters */
765 nbquarters = atoi(mstz_el[1]);
766 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
767 if (nbquarters < 0 || nbquarters > 79) {
768 printf("Invalid Number of Quarters \n");
769 return -1;
770 }
771 /* DST */
772 DST = atoi(mstz_el[2]);
773 printf("->Daylight Saving Time Adjustment : %d\n", DST);
774 if (DST < 0 || DST > 3) {
775 printf("Invalid DST Adjustment \n");
776 return -1;
777 }
778 /* 12345678
779 bits 123 = unit of # of quarters of an hour
780 bits 678 = # of quarters of an hour / 10
781 bit 5 = sign
782 */
783 i = nbquarters % 10;
784 i = i << 4;
785 i = i + nbquarters / 10 + 8 * sign;
786 /* options.mstz.v[0] = 0x69 ; */
787 /* options.mstz.v[1] = 0x01 ; */
788 options.mstz.v[0] = i;
789 options.mstz.v[1] = DST;
790 n = (i & 0x08) ? '-' : '+';
791 printf
792 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
793 n, nbquarters / 4, nbquarters % 4 * 15);
794 }
795
796 /* imeisv */
797 if (args_info.imeisv_given == 1) {
798 options.imeisv_given = 1;
799 if (strlen(args_info.imeisv_arg) != 16) {
800 printf("Invalid IMEI(SV)\n");
801 return -1;
802 }
803 options.imeisv.l = 8;
804 for (n = 0; n < 8; n++) {
805 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
806 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
807 options.imeisv.v[n] = 16 * b + a;
808 }
809 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
810 }
811
812 /* msisdn */
813 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
814 printf("Invalid MSISDN\n");
815 return -1;
816 }
817 options.msisdn.l = 1;
818 options.msisdn.v[0] = 0x91; /* International format */
819 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
820 if ((n % 2) == 0) {
821 options.msisdn.v[((int)n / 2) + 1] =
822 args_info.msisdn_arg[n] - 48 + 0xf0;
823 options.msisdn.l += 1;
824 } else {
825 options.msisdn.v[((int)n / 2) + 1] =
826 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
827 (args_info.msisdn_arg[n] - 48) * 16;
828 }
829 }
830 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
831
832 /* UID and PWD */
833 /* Might need to also insert stuff like DNS etc. */
834 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
835 (sizeof(options.pco.v) - 1)) {
836 printf("invalid UID and PWD\n");
837 return -1;
838 }
839 options.pco.l =
840 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
841 options.pco.v[0] = 0x80; /* PPP */
842 options.pco.v[1] = 0xc0; /* PAP */
843 options.pco.v[2] = 0x23;
844 options.pco.v[3] =
845 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
846 options.pco.v[4] = 0x01; /* Authenticate request */
847 options.pco.v[5] = 0x01;
848 options.pco.v[6] = 0x00; /* MSB of length */
849 options.pco.v[7] =
850 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
851 options.pco.v[8] = strlen(args_info.uid_arg);
852 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
853 options.pco.v[9 + strlen(args_info.uid_arg)] =
854 strlen(args_info.pwd_arg);
855 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
856 args_info.pwd_arg, strlen(args_info.pwd_arg));
857
858 /* createif */
859 options.createif = args_info.createif_flag;
860
861 /* net */
862 /* Store net as in_addr net and mask */
863 if (args_info.net_arg) {
Harald Welted12eab92017-08-02 19:49:47 +0200864 struct in46_addr in46;
Harald Weltebed35df2011-11-02 13:06:18 +0100865 if (ippool_aton
Harald Welted12eab92017-08-02 19:49:47 +0200866 (&in46, &options.prefixlen, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100867 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100868 "Invalid network address: %s!",
869 args_info.net_arg);
870 exit(1);
871 }
Harald Welted12eab92017-08-02 19:49:47 +0200872 options.net.s_addr = in46.v4.s_addr;
Harald Weltebed35df2011-11-02 13:06:18 +0100873 options.netaddr.s_addr = options.net.s_addr;
874 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000875
Harald Weltebed35df2011-11-02 13:06:18 +0100876 } else {
877 options.net.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200878 options.prefixlen = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100879 options.netaddr.s_addr = 0;
880 options.destaddr.s_addr = 0;
881 }
jjako193e8b12003-11-10 12:31:41 +0000882
Harald Weltebed35df2011-11-02 13:06:18 +0100883 /* ipup */
884 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000885
Harald Weltebed35df2011-11-02 13:06:18 +0100886 /* ipdown */
887 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000888
Harald Weltebed35df2011-11-02 13:06:18 +0100889 /* statedir */
890 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000891
Harald Weltebed35df2011-11-02 13:06:18 +0100892 /* defaultroute */
893 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000894
Harald Weltebed35df2011-11-02 13:06:18 +0100895 /* pinghost */
896 /* Store ping host as in_addr */
897 if (args_info.pinghost_arg) {
898 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100899 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100900 "Invalid ping host: %s!",
901 args_info.pinghost_arg);
902 return -1;
903 } else {
904 memcpy(&options.pinghost.s_addr, host->h_addr,
905 host->h_length);
906 printf("Using ping host: %s (%s)\n",
907 args_info.pinghost_arg,
908 inet_ntoa(options.pinghost));
909 }
910 }
jjakoa7cd2492003-04-11 09:40:12 +0000911
Harald Weltebed35df2011-11-02 13:06:18 +0100912 /* Other ping parameters */
913 options.pingrate = args_info.pingrate_arg;
914 options.pingsize = args_info.pingsize_arg;
915 options.pingcount = args_info.pingcount_arg;
916 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000917
Harald Weltebed35df2011-11-02 13:06:18 +0100918 /* norecovery */
919 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000920
Harald Weltebed35df2011-11-02 13:06:18 +0100921 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000922
923}
924
Harald Weltebed35df2011-11-02 13:06:18 +0100925int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
926{
927 unsigned int i;
928 printf("The packet looks like this:\n");
929 for (i = 0; i < len; i++) {
930 printf("%02x ", (unsigned char)*(char *)(pack + i));
931 if (!((i + 1) % 16))
932 printf("\n");
933 };
934 printf("\n");
935 return 0;
jjako52c24142002-12-16 13:33:51 +0000936}
937
Harald Weltebed35df2011-11-02 13:06:18 +0100938char *print_ipprot(int t)
939{
940 switch (t) {
941 case 1:
942 return "ICMP";
943 case 6:
944 return "TCP";
945 case 17:
946 return "UDP";
947 default:
948 return "Unknown";
949 };
jjako5da68452003-01-28 16:08:47 +0000950}
951
Harald Weltebed35df2011-11-02 13:06:18 +0100952char *print_icmptype(int t)
953{
954 static char *ttab[] = {
955 "Echo Reply",
956 "ICMP 1",
957 "ICMP 2",
958 "Dest Unreachable",
959 "Source Quench",
960 "Redirect",
961 "ICMP 6",
962 "ICMP 7",
963 "Echo",
964 "ICMP 9",
965 "ICMP 10",
966 "Time Exceeded",
967 "Parameter Problem",
968 "Timestamp",
969 "Timestamp Reply",
970 "Info Request",
971 "Info Reply"
972 };
973 if (t < 0 || t > 16)
974 return ("OUT-OF-RANGE");
975 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +0000976}
977
Harald Weltebed35df2011-11-02 13:06:18 +0100978int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
979{
980 unsigned int n;
981 uint64_t i64 = 0;
982 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
983 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +0000984
Harald Weltebed35df2011-11-02 13:06:18 +0100985 /* Convert to uint64_t from ul16_t format (most significant digit first) */
986 /* ul16_t format always starts with 0x91 to indicate international format */
987 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
988 for (n = 0; n < src->l; n++) {
989 if ((src->v[n] & 0x0f) != 0x0f) {
990 i64 *= 10;
991 i64 += src->v[n] & 0x0f;
992 }
993 if ((src->v[n] & 0xf0) != 0xf0) {
994 i64 *= 10;
995 i64 += (src->v[n] & 0xf0) >> 4;
996 }
997 }
jjako193e8b12003-11-10 12:31:41 +0000998
Harald Weltebed35df2011-11-02 13:06:18 +0100999 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001000
Harald Weltebed35df2011-11-02 13:06:18 +01001001 /* Generate array with least significant digit in first octet */
1002 while (i64) {
1003 msa[msalen++] = i64 % 10;
1004 i64 = i64 / 10;
1005 }
jjako193e8b12003-11-10 12:31:41 +00001006
Harald Weltebed35df2011-11-02 13:06:18 +01001007 /* Convert back to ul16_t format */
1008 for (n = 0; n < msalen; n++) {
1009 if ((n % 2) == 0) {
1010 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1011 dst->l += 1;
1012 } else {
1013 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1014 msa[msalen - n - 1] * 16;
1015 }
1016 }
jjako193e8b12003-11-10 12:31:41 +00001017
Harald Weltebed35df2011-11-02 13:06:18 +01001018 return 0;
jjako193e8b12003-11-10 12:31:41 +00001019
1020}
1021
Harald Weltebed35df2011-11-02 13:06:18 +01001022int imsi_add(uint64_t src, uint64_t * dst, int add)
1023{
1024 /* TODO: big endian / small endian ??? */
1025 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001026
Harald Weltebed35df2011-11-02 13:06:18 +01001027 /* Convert from uint64_t bcd to uint64_t integer format */
1028 /* The resulting integer format is multiplied by 10 */
1029 while (src) {
1030 if ((src & 0x0f) != 0x0f) {
1031 i64 *= 10;
1032 i64 += (src & 0x0f);
1033 }
1034 if ((src & 0xf0) != 0xf0) {
1035 i64 *= 10;
1036 i64 += (src & 0xf0) >> 4;
1037 }
1038 src = src >> 8;
1039 }
jjako193e8b12003-11-10 12:31:41 +00001040
Harald Weltebed35df2011-11-02 13:06:18 +01001041 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001042
Harald Weltebed35df2011-11-02 13:06:18 +01001043 *dst = 0;
1044 while (i64) {
1045 *dst = *dst << 4;
1046 *dst += (i64 % 10);
1047 i64 = i64 / 10;
1048 }
jjako193e8b12003-11-10 12:31:41 +00001049
Harald Weltebed35df2011-11-02 13:06:18 +01001050 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001051
Harald Weltebed35df2011-11-02 13:06:18 +01001052 return 0;
jjako193e8b12003-11-10 12:31:41 +00001053
1054}
1055
jjakoafb2a972003-01-29 21:04:13 +00001056/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001057int ping_timeout(struct timeval *tp)
1058{
1059 struct timezone tz;
1060 struct timeval tv;
1061 int diff;
1062 if ((options.pinghost.s_addr) && (2 == state) &&
1063 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1064 gettimeofday(&tv, &tz);
1065 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1066 tp->tv_sec = 0;
1067 if (diff > 0)
1068 tp->tv_usec = diff;
1069 else {
1070 /* For some reason we get packet loss if set to zero */
1071 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1072 tp->tv_usec = 0;
1073 }
1074 }
1075 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001076}
1077
jjako5da68452003-01-28 16:08:47 +00001078/* Print out statistics when at the end of ping sequence */
1079int ping_finish()
1080{
Harald Weltebed35df2011-11-02 13:06:18 +01001081 struct timezone tz;
1082 struct timeval tv;
1083 int elapsed;
1084 gettimeofday(&tv, &tz);
1085 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1086 printf("\n");
1087 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1088 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1089 elapsed / 1000000.0);
1090 printf("%d packets received, ", nreceived);
1091 if (ntransmitted) {
1092 if (nreceived > ntransmitted)
1093 printf("-- somebody's printing up packets!");
1094 else
1095 printf("%d%% packet loss",
1096 (int)(((ntransmitted - nreceived) * 100) /
1097 ntransmitted));
1098 }
1099 printf("\n");
1100 if (options.debug)
1101 printf("%d packets received in total\n", ntreceived);
1102 if (nreceived && tsum)
1103 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1104 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1105 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001106
Harald Weltebed35df2011-11-02 13:06:18 +01001107 ntransmitted = 0;
1108 return 0;
jjako5da68452003-01-28 16:08:47 +00001109}
1110
1111/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001112int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1113{
1114 struct timezone tz;
1115 struct timeval tv;
1116 struct timeval *tp;
1117 struct ip_ping *pingpack = pack;
1118 struct in_addr src;
1119 int triptime;
jjako5da68452003-01-28 16:08:47 +00001120
Harald Weltebed35df2011-11-02 13:06:18 +01001121 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001122
Harald Weltebed35df2011-11-02 13:06:18 +01001123 gettimeofday(&tv, &tz);
1124 if (options.debug)
1125 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001126
Harald Weltebed35df2011-11-02 13:06:18 +01001127 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1128 printf("packet too short (%d bytes) from %s\n", len,
1129 inet_ntoa(src));
1130 return 0;
1131 }
jjako5da68452003-01-28 16:08:47 +00001132
Harald Weltebed35df2011-11-02 13:06:18 +01001133 ntreceived++;
1134 if (pingpack->protocol != 1) {
1135 if (!options.pingquiet)
1136 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1137 len, inet_ntoa(src), pingpack->protocol,
1138 print_ipprot(pingpack->protocol));
1139 return 0;
1140 }
jjako5da68452003-01-28 16:08:47 +00001141
Harald Weltebed35df2011-11-02 13:06:18 +01001142 if (pingpack->type != 0) {
1143 if (!options.pingquiet)
1144 printf
1145 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1146 len, inet_ntoa(src), pingpack->type,
1147 print_icmptype(pingpack->type), pingpack->code);
1148 return 0;
1149 }
jjako5da68452003-01-28 16:08:47 +00001150
Harald Weltebed35df2011-11-02 13:06:18 +01001151 nreceived++;
1152 if (!options.pingquiet)
1153 printf("%d bytes from %s: icmp_seq=%d", len,
1154 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001155
Harald Weltebed35df2011-11-02 13:06:18 +01001156 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1157 gettimeofday(&tv, &tz);
1158 tp = (struct timeval *)pingpack->data;
1159 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1160 tv.tv_sec--;
1161 tv.tv_usec += 1000000;
1162 }
1163 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001164
Harald Weltebed35df2011-11-02 13:06:18 +01001165 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1166 tsum += triptime;
1167 if (triptime < tmin)
1168 tmin = triptime;
1169 if (triptime > tmax)
1170 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001171
Harald Weltebed35df2011-11-02 13:06:18 +01001172 if (!options.pingquiet)
1173 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001174
Harald Weltebed35df2011-11-02 13:06:18 +01001175 } else if (!options.pingquiet)
1176 printf("\n");
1177 return 0;
jjako5da68452003-01-28 16:08:47 +00001178}
1179
1180/* Create a new ping packet and send it off to peer. */
1181int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001182 struct in_addr *dst, int seq, unsigned int datasize)
1183{
jjako5da68452003-01-28 16:08:47 +00001184
Harald Weltebed35df2011-11-02 13:06:18 +01001185 struct ip_ping pack;
1186 uint16_t *p = (uint16_t *) & pack;
1187 uint8_t *p8 = (uint8_t *) & pack;
1188 struct in_addr src;
1189 unsigned int n;
1190 long int sum = 0;
1191 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001192
Harald Weltebed35df2011-11-02 13:06:18 +01001193 struct timezone tz;
1194 struct timeval *tp =
1195 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001196
Harald Weltebed35df2011-11-02 13:06:18 +01001197 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001198 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001199 "Ping size to large: %d!", datasize);
1200 return -1;
1201 }
jjako5da68452003-01-28 16:08:47 +00001202
Harald Weltebed35df2011-11-02 13:06:18 +01001203 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001204
Harald Weltebed35df2011-11-02 13:06:18 +01001205 pack.ipver = 0x45;
1206 pack.tos = 0x00;
1207 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1208 pack.fragid = 0x0000;
1209 pack.offset = 0x0040;
1210 pack.ttl = 0x40;
1211 pack.protocol = 0x01;
1212 pack.ipcheck = 0x0000;
1213 pack.src = src.s_addr;
1214 pack.dst = dst->s_addr;
1215 pack.type = 0x08;
1216 pack.code = 0x00;
1217 pack.checksum = 0x0000;
1218 pack.ident = 0x0000;
1219 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001220
Harald Weltebed35df2011-11-02 13:06:18 +01001221 /* Generate ICMP payload */
1222 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1223 for (n = 0; n < (datasize); n++)
1224 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001225
Harald Weltebed35df2011-11-02 13:06:18 +01001226 if (datasize >= sizeof(struct timeval))
1227 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001228
Harald Weltebed35df2011-11-02 13:06:18 +01001229 /* Calculate IP header checksum */
1230 p = (uint16_t *) & pack;
1231 count = CREATEPING_IP;
1232 sum = 0;
1233 while (count > 1) {
1234 sum += *p++;
1235 count -= 2;
1236 }
1237 while (sum >> 16)
1238 sum = (sum & 0xffff) + (sum >> 16);
1239 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001240
Harald Weltebed35df2011-11-02 13:06:18 +01001241 /* Calculate ICMP checksum */
1242 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1243 sum = 0;
1244 p = (uint16_t *) & pack;
1245 p += CREATEPING_IP / 2;
1246 while (count > 1) {
1247 sum += *p++;
1248 count -= 2;
1249 }
1250 if (count > 0)
1251 sum += *(unsigned char *)p;
1252 while (sum >> 16)
1253 sum = (sum & 0xffff) + (sum >> 16);
1254 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001255
Harald Weltebed35df2011-11-02 13:06:18 +01001256 ntransmitted++;
1257 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001258}
1259
Harald Weltebed35df2011-11-02 13:06:18 +01001260int delete_context(struct pdp_t *pdp)
1261{
1262
1263 if (tun && options.ipdown)
1264 tun_runscript(tun, options.ipdown);
1265
1266 ipdel((struct iphash_t *)pdp->peer);
1267 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1268
1269 if (1 == options.contexts)
1270 state = 5; /* Disconnected */
1271
1272 return 0;
1273}
jjakoa7cd2492003-04-11 09:40:12 +00001274
1275/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001276int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1277{
1278 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001279 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001280 struct iphdr *iph = (struct iphdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001281
Harald Welted12eab92017-08-02 19:49:47 +02001282 src.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +02001283 src.v4.s_addr = iph->saddr;
jjakoa7cd2492003-04-11 09:40:12 +00001284
Harald Weltebed35df2011-11-02 13:06:18 +01001285 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001286 printf("Dropping packet from invalid source address: %s\n",
Harald Welted12eab92017-08-02 19:49:47 +02001287 inet_ntoa(src.v4));
Harald Weltebed35df2011-11-02 13:06:18 +01001288 return 0;
1289 }
1290
1291 if (ipm->pdp) /* Check if a peer protocol is defined */
1292 gtp_data_req(gsn, ipm->pdp, pack, len);
1293 return 0;
jjako52c24142002-12-16 13:33:51 +00001294}
1295
Harald Weltebed35df2011-11-02 13:06:18 +01001296int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1297{
Harald Welted12eab92017-08-02 19:49:47 +02001298 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001299
Harald Weltebed35df2011-11-02 13:06:18 +01001300 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001301
Harald Weltebed35df2011-11-02 13:06:18 +01001302 if (cause < 0) {
1303 printf("Create PDP Context Request timed out\n");
1304 if (iph->pdp->version == 1) {
1305 printf("Retrying with version 0\n");
1306 iph->pdp->version = 0;
1307 gtp_create_context_req(gsn, iph->pdp, iph);
1308 return 0;
1309 } else {
1310 state = 0;
1311 pdp_freepdp(iph->pdp);
1312 iph->pdp = NULL;
1313 return EOF;
1314 }
1315 }
jjako2c381332003-10-21 19:09:53 +00001316
Harald Weltebed35df2011-11-02 13:06:18 +01001317 if (cause != 128) {
1318 printf
1319 ("Received create PDP context response. Cause value: %d\n",
1320 cause);
1321 state = 0;
1322 pdp_freepdp(iph->pdp);
1323 iph->pdp = NULL;
1324 return EOF; /* Not what we expected */
1325 }
jjako52c24142002-12-16 13:33:51 +00001326
Harald Weltea0d281d2017-08-02 21:48:16 +02001327 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001328 printf
1329 ("Received create PDP context response. Cause value: %d\n",
1330 cause);
1331 pdp_freepdp(iph->pdp);
1332 iph->pdp = NULL;
1333 state = 0;
1334 return EOF; /* Not a valid IP address */
1335 }
jjakoa7cd2492003-04-11 09:40:12 +00001336
Harald Weltebed35df2011-11-02 13:06:18 +01001337 printf("Received create PDP context response. IP address: %s\n",
Harald Welted12eab92017-08-02 19:49:47 +02001338 inet_ntoa(addr.v4));
jjakoa7cd2492003-04-11 09:40:12 +00001339
Harald Weltebed35df2011-11-02 13:06:18 +01001340 if ((options.createif) && (!options.net.s_addr)) {
1341 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +00001342#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +01001343 inet_aton("255.255.255.255", &m);
jjako1d3db972004-01-16 09:56:56 +00001344#else
Harald Weltebed35df2011-11-02 13:06:18 +01001345 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +00001346#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001347 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001348 tun_addaddr(tun, &addr.v4, &addr.v4, &m);
Harald Weltebed35df2011-11-02 13:06:18 +01001349 if (options.defaultroute) {
1350 struct in_addr rm;
1351 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001352 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001353 }
1354 if (options.ipup)
1355 tun_runscript(tun, options.ipup);
1356 }
jjako52c24142002-12-16 13:33:51 +00001357
Harald Weltebed35df2011-11-02 13:06:18 +01001358 ipset((struct iphash_t *)pdp->peer, &addr);
1359
1360 state = 2; /* Connected */
1361
1362 return 0;
jjako52c24142002-12-16 13:33:51 +00001363}
1364
Harald Weltebed35df2011-11-02 13:06:18 +01001365int delete_pdp_conf(struct pdp_t *pdp, int cause)
1366{
1367 printf("Received delete PDP context response. Cause value: %d\n",
1368 cause);
1369 return 0;
jjako52c24142002-12-16 13:33:51 +00001370}
1371
Harald Weltebed35df2011-11-02 13:06:18 +01001372int echo_conf(int recovery)
1373{
jjako91aaf222003-10-22 10:09:32 +00001374
Harald Weltebed35df2011-11-02 13:06:18 +01001375 if (recovery < 0) {
1376 printf("Echo Request timed out\n");
1377 if (echoversion == 1) {
1378 printf("Retrying with version 0\n");
1379 echoversion = 0;
1380 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1381 return 0;
1382 } else {
1383 state = 0;
1384 return EOF;
1385 }
1386 } else {
1387 printf("Received echo response\n");
1388 if (!options.contexts)
1389 state = 5;
1390 }
1391 return 0;
jjako52c24142002-12-16 13:33:51 +00001392}
1393
Harald Weltebed35df2011-11-02 13:06:18 +01001394int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1395{
1396 /* if (cause < 0) return 0; Some error occurred. We don't care */
1397 switch (type) {
1398 case GTP_ECHO_REQ:
1399 return echo_conf(cause);
1400 case GTP_CREATE_PDP_REQ:
1401 return create_pdp_conf(pdp, cbp, cause);
1402 case GTP_DELETE_PDP_REQ:
1403 if (cause != 128)
1404 return 0; /* Request not accepted. We don't care */
1405 return delete_pdp_conf(pdp, cause);
1406 default:
1407 return 0;
1408 }
jjako52c24142002-12-16 13:33:51 +00001409}
1410
Harald Weltebed35df2011-11-02 13:06:18 +01001411int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1412{
1413 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1414 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001415}
1416
1417int main(int argc, char **argv)
1418{
Harald Weltebed35df2011-11-02 13:06:18 +01001419 fd_set fds; /* For select() */
1420 struct timeval idleTime; /* How long to select() */
1421 struct pdp_t *pdp;
1422 int n;
1423 int starttime = time(NULL); /* Time program was started */
1424 int stoptime = 0; /* Time to exit */
1425 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001426 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001427
Harald Weltebed35df2011-11-02 13:06:18 +01001428 struct timezone tz; /* Used for calculating ping times */
1429 struct timeval tv;
1430 int diff;
jjako52c24142002-12-16 13:33:51 +00001431
bjovana8f71eb2017-02-24 17:39:20 +01001432 signal(SIGTERM, signal_handler);
1433 signal(SIGHUP, signal_handler);
1434 signal(SIGINT, signal_handler);
1435
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001436 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001437
Harald Weltebed35df2011-11-02 13:06:18 +01001438 /* Process options given in configuration file and command line */
1439 if (process_options(argc, argv))
1440 exit(1);
jjako52c24142002-12-16 13:33:51 +00001441
Harald Weltebed35df2011-11-02 13:06:18 +01001442 printf("\nInitialising GTP library\n");
1443 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001444 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001445 exit(1);
1446 }
1447 if (gsn->fd0 > maxfd)
1448 maxfd = gsn->fd0;
1449 if (gsn->fd1c > maxfd)
1450 maxfd = gsn->fd1c;
1451 if (gsn->fd1u > maxfd)
1452 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001453
Harald Weltebed35df2011-11-02 13:06:18 +01001454 gtp_set_cb_delete_context(gsn, delete_context);
1455 gtp_set_cb_conf(gsn, conf);
1456 if (options.createif)
1457 gtp_set_cb_data_ind(gsn, encaps_tun);
1458 else
1459 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001460
Harald Weltebed35df2011-11-02 13:06:18 +01001461 if (options.createif) {
1462 printf("Setting up interface\n");
1463 /* Create a tunnel interface */
1464 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001465 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001466 "Failed to create tun");
1467 exit(1);
1468 }
1469 tun_set_cb_ind(tun, cb_tun_ind);
1470 if (tun->fd > maxfd)
1471 maxfd = tun->fd;
1472 }
jjakoa7cd2492003-04-11 09:40:12 +00001473
Harald Weltebed35df2011-11-02 13:06:18 +01001474 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001475 struct in_addr mask;
1476 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001477 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001478 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001479 if (options.defaultroute) {
1480 struct in_addr rm;
1481 rm.s_addr = 0;
1482 tun_addroute(tun, &rm, &options.destaddr, &rm);
1483 }
1484 if (options.ipup)
1485 tun_runscript(tun, options.ipup);
1486 }
jjakoa7cd2492003-04-11 09:40:12 +00001487
Harald Weltebed35df2011-11-02 13:06:18 +01001488 /* Initialise hash tables */
1489 memset(&iphash, 0, sizeof(iphash));
1490 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001491
Harald Weltebed35df2011-11-02 13:06:18 +01001492 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001493
Harald Weltebed35df2011-11-02 13:06:18 +01001494 /* See if anybody is there */
1495 printf("Sending off echo request\n");
1496 echoversion = options.gtpversion;
1497 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001498
Harald Weltebed35df2011-11-02 13:06:18 +01001499 for (n = 0; n < options.contexts; n++) {
1500 uint64_t myimsi;
1501 printf("Setting up PDP context #%d\n", n);
1502 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001503
Harald Weltebed35df2011-11-02 13:06:18 +01001504 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001505
Harald Weltebed35df2011-11-02 13:06:18 +01001506 /* Allocated here. */
1507 /* If create context failes we have to deallocate ourselves. */
1508 /* Otherwise it is deallocated by gtplib */
1509 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001510
Harald Weltebed35df2011-11-02 13:06:18 +01001511 pdp->peer = &iparr[n];
1512 pdp->ipif = tun; /* TODO */
1513 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001514
Harald Weltebed35df2011-11-02 13:06:18 +01001515 if (options.gtpversion == 0) {
1516 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001517 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001518 "QoS length too big");
1519 exit(1);
1520 } else {
1521 memcpy(pdp->qos_req0, options.qos.v,
1522 options.qos.l);
1523 }
1524 }
jjakoa7cd2492003-04-11 09:40:12 +00001525
Harald Weltebed35df2011-11-02 13:06:18 +01001526 pdp->qos_req.l = options.qos.l;
1527 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001528
Harald Weltebed35df2011-11-02 13:06:18 +01001529 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001530
Harald Weltebed35df2011-11-02 13:06:18 +01001531 pdp->rattype.l = options.rattype.l;
1532 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1533 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001534
Harald Weltebed35df2011-11-02 13:06:18 +01001535 pdp->userloc.l = options.userloc.l;
1536 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1537 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001538
Harald Weltebed35df2011-11-02 13:06:18 +01001539 pdp->rai.l = options.rai.l;
1540 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1541 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001542
Harald Weltebed35df2011-11-02 13:06:18 +01001543 pdp->mstz.l = options.mstz.l;
1544 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1545 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001546
Harald Weltebed35df2011-11-02 13:06:18 +01001547 pdp->imeisv.l = options.imeisv.l;
1548 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1549 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001550
Harald Weltebed35df2011-11-02 13:06:18 +01001551 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001552
Harald Weltebed35df2011-11-02 13:06:18 +01001553 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001554 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001555 "APN length too big");
1556 exit(1);
1557 } else {
1558 pdp->apn_use.l = options.apn.l;
1559 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1560 }
jjako193e8b12003-11-10 12:31:41 +00001561
Harald Weltebed35df2011-11-02 13:06:18 +01001562 pdp->gsnlc.l = sizeof(options.listen);
1563 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1564 pdp->gsnlu.l = sizeof(options.listen);
1565 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001566
Harald Weltebed35df2011-11-02 13:06:18 +01001567 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001568 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001569 "MSISDN length too big");
1570 exit(1);
1571 } else {
1572 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1573 }
jjakob62c3dd2004-05-27 18:51:55 +00001574
Harald Weltebed35df2011-11-02 13:06:18 +01001575 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
jjako52c24142002-12-16 13:33:51 +00001576
Harald Weltebed35df2011-11-02 13:06:18 +01001577 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001578 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001579 "PCO length too big");
1580 exit(1);
1581 } else {
1582 pdp->pco_req.l = options.pco.l;
1583 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1584 }
jjako52c24142002-12-16 13:33:51 +00001585
Harald Weltebed35df2011-11-02 13:06:18 +01001586 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001587
Harald Weltebed35df2011-11-02 13:06:18 +01001588 pdp->hisaddr0 = options.remote;
1589 pdp->hisaddr1 = options.remote;
1590
1591 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1592 512 = Flat rate, 256 = Hot billing */
1593
1594 /* Create context */
1595 /* We send this of once. Retransmissions are handled by gtplib */
1596 gtp_create_context_req(gsn, pdp, &iparr[n]);
1597 }
1598
1599 state = 1; /* Enter wait_connection state */
1600
1601 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001602
jjako52c24142002-12-16 13:33:51 +00001603 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001604 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001605 /******************************************************************/
1606
Harald Weltebed35df2011-11-02 13:06:18 +01001607 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001608
Harald Weltebed35df2011-11-02 13:06:18 +01001609 /* Take down client after timeout after disconnect */
1610 if ((4 == state) && ((stoptime) <= time(NULL))) {
1611 state = 5;
1612 }
jjako7b8fad42003-07-07 14:37:42 +00001613
Harald Weltebed35df2011-11-02 13:06:18 +01001614 /* Take down client after timelimit timeout */
1615 if ((2 == state) && (options.timelimit) &&
1616 ((starttime + options.timelimit) <= time(NULL))) {
1617 state = 3;
1618 }
jjako7b8fad42003-07-07 14:37:42 +00001619
Harald Weltebed35df2011-11-02 13:06:18 +01001620 /* Take down client after ping timeout */
1621 if ((2 == state) && (pingtimeout)
1622 && (pingtimeout <= time(NULL))) {
1623 state = 3;
1624 }
jjako7b8fad42003-07-07 14:37:42 +00001625
Harald Weltebed35df2011-11-02 13:06:18 +01001626 /* Set pingtimeout for later disconnection */
1627 if (options.pingcount && ntransmitted >= options.pingcount) {
1628 pingtimeout = time(NULL) + 5; /* Extra seconds */
1629 }
jjako7b8fad42003-07-07 14:37:42 +00001630
Harald Weltebed35df2011-11-02 13:06:18 +01001631 /* Print statistics if no more ping packets are missing */
1632 if (ntransmitted && options.pingcount
1633 && nreceived >= options.pingcount) {
1634 ping_finish();
1635 if (!options.createif)
1636 state = 3;
1637 }
jjako7b8fad42003-07-07 14:37:42 +00001638
Harald Weltebed35df2011-11-02 13:06:18 +01001639 /* Send off disconnect */
1640 if (3 == state) {
1641 state = 4;
1642 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1643 for (n = 0; n < options.contexts; n++) {
1644 /* Delete context */
1645 printf("Disconnecting PDP context #%d\n", n);
1646 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1647 1);
1648 if ((options.pinghost.s_addr != 0)
1649 && ntransmitted)
1650 ping_finish();
1651 }
1652 }
jjako7b8fad42003-07-07 14:37:42 +00001653
Harald Weltebed35df2011-11-02 13:06:18 +01001654 /* Send of ping packets */
1655 diff = 0;
1656 while ((diff <= 0) &&
1657 /* Send off an ICMP ping packet */
1658 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1659 ((pingseq < options.pingcount)
1660 || (options.pingcount == 0))) {
1661 if (!pingseq)
1662 gettimeofday(&firstping, &tz); /* Set time of first ping */
1663 gettimeofday(&tv, &tz);
1664 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1665 if (diff <= 0) {
1666 if (options.debug)
1667 printf("Create_ping %d\n", diff);
1668 create_ping(gsn,
1669 iparr[pingseq %
1670 options.contexts].pdp,
1671 &options.pinghost, pingseq,
1672 options.pingsize);
1673 pingseq++;
1674 }
1675 }
jjako5da68452003-01-28 16:08:47 +00001676
Harald Weltebed35df2011-11-02 13:06:18 +01001677 FD_ZERO(&fds);
1678 if (tun)
1679 FD_SET(tun->fd, &fds);
1680 FD_SET(gsn->fd0, &fds);
1681 FD_SET(gsn->fd1c, &fds);
1682 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001683
Harald Weltebed35df2011-11-02 13:06:18 +01001684 gtp_retranstimeout(gsn, &idleTime);
1685 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001686
Harald Weltebed35df2011-11-02 13:06:18 +01001687 if (options.debug)
1688 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1689 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001690
bjovana8f71eb2017-02-24 17:39:20 +01001691 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001692 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1693 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001694 if (errno == EINTR)
1695 signal_received = 1;
1696 else
1697 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1698 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001699 break;
1700 case 0:
1701 gtp_retrans(gsn); /* Only retransmit if nothing else */
1702 break;
1703 default:
1704 break;
1705 }
1706
bjovana8f71eb2017-02-24 17:39:20 +01001707 if (!signal_received) {
1708
1709 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1710 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1711 "TUN decaps failed");
1712 }
1713
1714 if (FD_ISSET(gsn->fd0, &fds))
1715 gtp_decaps0(gsn);
1716
1717 if (FD_ISSET(gsn->fd1c, &fds))
1718 gtp_decaps1c(gsn);
1719
1720 if (FD_ISSET(gsn->fd1u, &fds))
1721 gtp_decaps1u(gsn);
1722
Harald Weltebed35df2011-11-02 13:06:18 +01001723 }
Harald Weltebed35df2011-11-02 13:06:18 +01001724 }
1725
1726 gtp_free(gsn); /* Clean up the gsn instance */
1727
1728 if (options.createif)
1729 tun_free(tun);
1730
1731 if (0 == state)
1732 exit(1); /* Indicate error */
1733
1734 return 0;
jjako52c24142002-12-16 13:33:51 +00001735}