blob: 8c9cfd3688f89a37f8de23b78da65d9bf0634486 [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;
jjakoc6762cf2004-04-28 14:52:58 +0000873#if defined (__sun__)
Harald Welted12eab92017-08-02 19:49:47 +0200874 options.netaddrs_addr = htonl(ntohl(options.net.s_addr) + 1);
Harald Weltebed35df2011-11-02 13:06:18 +0100875 options.destaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
jjakoc6762cf2004-04-28 14:52:58 +0000876#else
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#endif
880
Harald Weltebed35df2011-11-02 13:06:18 +0100881 } else {
882 options.net.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +0200883 options.prefixlen = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100884 options.netaddr.s_addr = 0;
885 options.destaddr.s_addr = 0;
886 }
jjako193e8b12003-11-10 12:31:41 +0000887
Harald Weltebed35df2011-11-02 13:06:18 +0100888 /* ipup */
889 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000890
Harald Weltebed35df2011-11-02 13:06:18 +0100891 /* ipdown */
892 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000893
Harald Weltebed35df2011-11-02 13:06:18 +0100894 /* statedir */
895 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000896
Harald Weltebed35df2011-11-02 13:06:18 +0100897 /* defaultroute */
898 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000899
Harald Weltebed35df2011-11-02 13:06:18 +0100900 /* pinghost */
901 /* Store ping host as in_addr */
902 if (args_info.pinghost_arg) {
903 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100904 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100905 "Invalid ping host: %s!",
906 args_info.pinghost_arg);
907 return -1;
908 } else {
909 memcpy(&options.pinghost.s_addr, host->h_addr,
910 host->h_length);
911 printf("Using ping host: %s (%s)\n",
912 args_info.pinghost_arg,
913 inet_ntoa(options.pinghost));
914 }
915 }
jjakoa7cd2492003-04-11 09:40:12 +0000916
Harald Weltebed35df2011-11-02 13:06:18 +0100917 /* Other ping parameters */
918 options.pingrate = args_info.pingrate_arg;
919 options.pingsize = args_info.pingsize_arg;
920 options.pingcount = args_info.pingcount_arg;
921 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000922
Harald Weltebed35df2011-11-02 13:06:18 +0100923 /* norecovery */
924 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000925
Harald Weltebed35df2011-11-02 13:06:18 +0100926 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000927
928}
929
Harald Weltebed35df2011-11-02 13:06:18 +0100930int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
931{
932 unsigned int i;
933 printf("The packet looks like this:\n");
934 for (i = 0; i < len; i++) {
935 printf("%02x ", (unsigned char)*(char *)(pack + i));
936 if (!((i + 1) % 16))
937 printf("\n");
938 };
939 printf("\n");
940 return 0;
jjako52c24142002-12-16 13:33:51 +0000941}
942
Harald Weltebed35df2011-11-02 13:06:18 +0100943char *print_ipprot(int t)
944{
945 switch (t) {
946 case 1:
947 return "ICMP";
948 case 6:
949 return "TCP";
950 case 17:
951 return "UDP";
952 default:
953 return "Unknown";
954 };
jjako5da68452003-01-28 16:08:47 +0000955}
956
Harald Weltebed35df2011-11-02 13:06:18 +0100957char *print_icmptype(int t)
958{
959 static char *ttab[] = {
960 "Echo Reply",
961 "ICMP 1",
962 "ICMP 2",
963 "Dest Unreachable",
964 "Source Quench",
965 "Redirect",
966 "ICMP 6",
967 "ICMP 7",
968 "Echo",
969 "ICMP 9",
970 "ICMP 10",
971 "Time Exceeded",
972 "Parameter Problem",
973 "Timestamp",
974 "Timestamp Reply",
975 "Info Request",
976 "Info Reply"
977 };
978 if (t < 0 || t > 16)
979 return ("OUT-OF-RANGE");
980 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +0000981}
982
Harald Weltebed35df2011-11-02 13:06:18 +0100983int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
984{
985 unsigned int n;
986 uint64_t i64 = 0;
987 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
988 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +0000989
Harald Weltebed35df2011-11-02 13:06:18 +0100990 /* Convert to uint64_t from ul16_t format (most significant digit first) */
991 /* ul16_t format always starts with 0x91 to indicate international format */
992 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
993 for (n = 0; n < src->l; n++) {
994 if ((src->v[n] & 0x0f) != 0x0f) {
995 i64 *= 10;
996 i64 += src->v[n] & 0x0f;
997 }
998 if ((src->v[n] & 0xf0) != 0xf0) {
999 i64 *= 10;
1000 i64 += (src->v[n] & 0xf0) >> 4;
1001 }
1002 }
jjako193e8b12003-11-10 12:31:41 +00001003
Harald Weltebed35df2011-11-02 13:06:18 +01001004 i64 += add;
jjako193e8b12003-11-10 12:31:41 +00001005
Harald Weltebed35df2011-11-02 13:06:18 +01001006 /* Generate array with least significant digit in first octet */
1007 while (i64) {
1008 msa[msalen++] = i64 % 10;
1009 i64 = i64 / 10;
1010 }
jjako193e8b12003-11-10 12:31:41 +00001011
Harald Weltebed35df2011-11-02 13:06:18 +01001012 /* Convert back to ul16_t format */
1013 for (n = 0; n < msalen; n++) {
1014 if ((n % 2) == 0) {
1015 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1016 dst->l += 1;
1017 } else {
1018 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1019 msa[msalen - n - 1] * 16;
1020 }
1021 }
jjako193e8b12003-11-10 12:31:41 +00001022
Harald Weltebed35df2011-11-02 13:06:18 +01001023 return 0;
jjako193e8b12003-11-10 12:31:41 +00001024
1025}
1026
Harald Weltebed35df2011-11-02 13:06:18 +01001027int imsi_add(uint64_t src, uint64_t * dst, int add)
1028{
1029 /* TODO: big endian / small endian ??? */
1030 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001031
Harald Weltebed35df2011-11-02 13:06:18 +01001032 /* Convert from uint64_t bcd to uint64_t integer format */
1033 /* The resulting integer format is multiplied by 10 */
1034 while (src) {
1035 if ((src & 0x0f) != 0x0f) {
1036 i64 *= 10;
1037 i64 += (src & 0x0f);
1038 }
1039 if ((src & 0xf0) != 0xf0) {
1040 i64 *= 10;
1041 i64 += (src & 0xf0) >> 4;
1042 }
1043 src = src >> 8;
1044 }
jjako193e8b12003-11-10 12:31:41 +00001045
Harald Weltebed35df2011-11-02 13:06:18 +01001046 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001047
Harald Weltebed35df2011-11-02 13:06:18 +01001048 *dst = 0;
1049 while (i64) {
1050 *dst = *dst << 4;
1051 *dst += (i64 % 10);
1052 i64 = i64 / 10;
1053 }
jjako193e8b12003-11-10 12:31:41 +00001054
Harald Weltebed35df2011-11-02 13:06:18 +01001055 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001056
Harald Weltebed35df2011-11-02 13:06:18 +01001057 return 0;
jjako193e8b12003-11-10 12:31:41 +00001058
1059}
1060
jjakoafb2a972003-01-29 21:04:13 +00001061/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001062int ping_timeout(struct timeval *tp)
1063{
1064 struct timezone tz;
1065 struct timeval tv;
1066 int diff;
1067 if ((options.pinghost.s_addr) && (2 == state) &&
1068 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1069 gettimeofday(&tv, &tz);
1070 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1071 tp->tv_sec = 0;
1072 if (diff > 0)
1073 tp->tv_usec = diff;
1074 else {
1075 /* For some reason we get packet loss if set to zero */
1076 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1077 tp->tv_usec = 0;
1078 }
1079 }
1080 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001081}
1082
jjako5da68452003-01-28 16:08:47 +00001083/* Print out statistics when at the end of ping sequence */
1084int ping_finish()
1085{
Harald Weltebed35df2011-11-02 13:06:18 +01001086 struct timezone tz;
1087 struct timeval tv;
1088 int elapsed;
1089 gettimeofday(&tv, &tz);
1090 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1091 printf("\n");
1092 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1093 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1094 elapsed / 1000000.0);
1095 printf("%d packets received, ", nreceived);
1096 if (ntransmitted) {
1097 if (nreceived > ntransmitted)
1098 printf("-- somebody's printing up packets!");
1099 else
1100 printf("%d%% packet loss",
1101 (int)(((ntransmitted - nreceived) * 100) /
1102 ntransmitted));
1103 }
1104 printf("\n");
1105 if (options.debug)
1106 printf("%d packets received in total\n", ntreceived);
1107 if (nreceived && tsum)
1108 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1109 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1110 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001111
Harald Weltebed35df2011-11-02 13:06:18 +01001112 ntransmitted = 0;
1113 return 0;
jjako5da68452003-01-28 16:08:47 +00001114}
1115
1116/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001117int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1118{
1119 struct timezone tz;
1120 struct timeval tv;
1121 struct timeval *tp;
1122 struct ip_ping *pingpack = pack;
1123 struct in_addr src;
1124 int triptime;
jjako5da68452003-01-28 16:08:47 +00001125
Harald Weltebed35df2011-11-02 13:06:18 +01001126 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001127
Harald Weltebed35df2011-11-02 13:06:18 +01001128 gettimeofday(&tv, &tz);
1129 if (options.debug)
1130 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001131
Harald Weltebed35df2011-11-02 13:06:18 +01001132 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1133 printf("packet too short (%d bytes) from %s\n", len,
1134 inet_ntoa(src));
1135 return 0;
1136 }
jjako5da68452003-01-28 16:08:47 +00001137
Harald Weltebed35df2011-11-02 13:06:18 +01001138 ntreceived++;
1139 if (pingpack->protocol != 1) {
1140 if (!options.pingquiet)
1141 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1142 len, inet_ntoa(src), pingpack->protocol,
1143 print_ipprot(pingpack->protocol));
1144 return 0;
1145 }
jjako5da68452003-01-28 16:08:47 +00001146
Harald Weltebed35df2011-11-02 13:06:18 +01001147 if (pingpack->type != 0) {
1148 if (!options.pingquiet)
1149 printf
1150 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1151 len, inet_ntoa(src), pingpack->type,
1152 print_icmptype(pingpack->type), pingpack->code);
1153 return 0;
1154 }
jjako5da68452003-01-28 16:08:47 +00001155
Harald Weltebed35df2011-11-02 13:06:18 +01001156 nreceived++;
1157 if (!options.pingquiet)
1158 printf("%d bytes from %s: icmp_seq=%d", len,
1159 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001160
Harald Weltebed35df2011-11-02 13:06:18 +01001161 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1162 gettimeofday(&tv, &tz);
1163 tp = (struct timeval *)pingpack->data;
1164 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1165 tv.tv_sec--;
1166 tv.tv_usec += 1000000;
1167 }
1168 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001169
Harald Weltebed35df2011-11-02 13:06:18 +01001170 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1171 tsum += triptime;
1172 if (triptime < tmin)
1173 tmin = triptime;
1174 if (triptime > tmax)
1175 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001176
Harald Weltebed35df2011-11-02 13:06:18 +01001177 if (!options.pingquiet)
1178 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001179
Harald Weltebed35df2011-11-02 13:06:18 +01001180 } else if (!options.pingquiet)
1181 printf("\n");
1182 return 0;
jjako5da68452003-01-28 16:08:47 +00001183}
1184
1185/* Create a new ping packet and send it off to peer. */
1186int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001187 struct in_addr *dst, int seq, unsigned int datasize)
1188{
jjako5da68452003-01-28 16:08:47 +00001189
Harald Weltebed35df2011-11-02 13:06:18 +01001190 struct ip_ping pack;
1191 uint16_t *p = (uint16_t *) & pack;
1192 uint8_t *p8 = (uint8_t *) & pack;
1193 struct in_addr src;
1194 unsigned int n;
1195 long int sum = 0;
1196 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001197
Harald Weltebed35df2011-11-02 13:06:18 +01001198 struct timezone tz;
1199 struct timeval *tp =
1200 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001201
Harald Weltebed35df2011-11-02 13:06:18 +01001202 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001203 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001204 "Ping size to large: %d!", datasize);
1205 return -1;
1206 }
jjako5da68452003-01-28 16:08:47 +00001207
Harald Weltebed35df2011-11-02 13:06:18 +01001208 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001209
Harald Weltebed35df2011-11-02 13:06:18 +01001210 pack.ipver = 0x45;
1211 pack.tos = 0x00;
1212 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1213 pack.fragid = 0x0000;
1214 pack.offset = 0x0040;
1215 pack.ttl = 0x40;
1216 pack.protocol = 0x01;
1217 pack.ipcheck = 0x0000;
1218 pack.src = src.s_addr;
1219 pack.dst = dst->s_addr;
1220 pack.type = 0x08;
1221 pack.code = 0x00;
1222 pack.checksum = 0x0000;
1223 pack.ident = 0x0000;
1224 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001225
Harald Weltebed35df2011-11-02 13:06:18 +01001226 /* Generate ICMP payload */
1227 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1228 for (n = 0; n < (datasize); n++)
1229 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001230
Harald Weltebed35df2011-11-02 13:06:18 +01001231 if (datasize >= sizeof(struct timeval))
1232 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001233
Harald Weltebed35df2011-11-02 13:06:18 +01001234 /* Calculate IP header checksum */
1235 p = (uint16_t *) & pack;
1236 count = CREATEPING_IP;
1237 sum = 0;
1238 while (count > 1) {
1239 sum += *p++;
1240 count -= 2;
1241 }
1242 while (sum >> 16)
1243 sum = (sum & 0xffff) + (sum >> 16);
1244 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001245
Harald Weltebed35df2011-11-02 13:06:18 +01001246 /* Calculate ICMP checksum */
1247 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1248 sum = 0;
1249 p = (uint16_t *) & pack;
1250 p += CREATEPING_IP / 2;
1251 while (count > 1) {
1252 sum += *p++;
1253 count -= 2;
1254 }
1255 if (count > 0)
1256 sum += *(unsigned char *)p;
1257 while (sum >> 16)
1258 sum = (sum & 0xffff) + (sum >> 16);
1259 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001260
Harald Weltebed35df2011-11-02 13:06:18 +01001261 ntransmitted++;
1262 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001263}
1264
Harald Weltebed35df2011-11-02 13:06:18 +01001265int delete_context(struct pdp_t *pdp)
1266{
1267
1268 if (tun && options.ipdown)
1269 tun_runscript(tun, options.ipdown);
1270
1271 ipdel((struct iphash_t *)pdp->peer);
1272 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1273
1274 if (1 == options.contexts)
1275 state = 5; /* Disconnected */
1276
1277 return 0;
1278}
jjakoa7cd2492003-04-11 09:40:12 +00001279
1280/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001281int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1282{
1283 struct iphash_t *ipm;
Harald Welted12eab92017-08-02 19:49:47 +02001284 struct in46_addr src;
Harald Welte63ebccd2017-08-02 21:10:09 +02001285 struct iphdr *iph = (struct iphdr *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001286
Harald Welted12eab92017-08-02 19:49:47 +02001287 src.len = 4;
Harald Welte63ebccd2017-08-02 21:10:09 +02001288 src.v4.s_addr = iph->saddr;
jjakoa7cd2492003-04-11 09:40:12 +00001289
Harald Weltebed35df2011-11-02 13:06:18 +01001290 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001291 printf("Dropping packet from invalid source address: %s\n",
Harald Welted12eab92017-08-02 19:49:47 +02001292 inet_ntoa(src.v4));
Harald Weltebed35df2011-11-02 13:06:18 +01001293 return 0;
1294 }
1295
1296 if (ipm->pdp) /* Check if a peer protocol is defined */
1297 gtp_data_req(gsn, ipm->pdp, pack, len);
1298 return 0;
jjako52c24142002-12-16 13:33:51 +00001299}
1300
Harald Weltebed35df2011-11-02 13:06:18 +01001301int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1302{
Harald Welted12eab92017-08-02 19:49:47 +02001303 struct in46_addr addr;
jjako52c24142002-12-16 13:33:51 +00001304
Harald Weltebed35df2011-11-02 13:06:18 +01001305 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001306
Harald Weltebed35df2011-11-02 13:06:18 +01001307 if (cause < 0) {
1308 printf("Create PDP Context Request timed out\n");
1309 if (iph->pdp->version == 1) {
1310 printf("Retrying with version 0\n");
1311 iph->pdp->version = 0;
1312 gtp_create_context_req(gsn, iph->pdp, iph);
1313 return 0;
1314 } else {
1315 state = 0;
1316 pdp_freepdp(iph->pdp);
1317 iph->pdp = NULL;
1318 return EOF;
1319 }
1320 }
jjako2c381332003-10-21 19:09:53 +00001321
Harald Weltebed35df2011-11-02 13:06:18 +01001322 if (cause != 128) {
1323 printf
1324 ("Received create PDP context response. Cause value: %d\n",
1325 cause);
1326 state = 0;
1327 pdp_freepdp(iph->pdp);
1328 iph->pdp = NULL;
1329 return EOF; /* Not what we expected */
1330 }
jjako52c24142002-12-16 13:33:51 +00001331
Harald Weltea0d281d2017-08-02 21:48:16 +02001332 if (in46a_from_eua(&pdp->eua, &addr)) {
Harald Weltebed35df2011-11-02 13:06:18 +01001333 printf
1334 ("Received create PDP context response. Cause value: %d\n",
1335 cause);
1336 pdp_freepdp(iph->pdp);
1337 iph->pdp = NULL;
1338 state = 0;
1339 return EOF; /* Not a valid IP address */
1340 }
jjakoa7cd2492003-04-11 09:40:12 +00001341
Harald Weltebed35df2011-11-02 13:06:18 +01001342 printf("Received create PDP context response. IP address: %s\n",
Harald Welted12eab92017-08-02 19:49:47 +02001343 inet_ntoa(addr.v4));
jjakoa7cd2492003-04-11 09:40:12 +00001344
Harald Weltebed35df2011-11-02 13:06:18 +01001345 if ((options.createif) && (!options.net.s_addr)) {
1346 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +00001347#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +01001348 inet_aton("255.255.255.255", &m);
jjako1d3db972004-01-16 09:56:56 +00001349#else
Harald Weltebed35df2011-11-02 13:06:18 +01001350 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +00001351#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001352 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001353 tun_addaddr(tun, &addr.v4, &addr.v4, &m);
Harald Weltebed35df2011-11-02 13:06:18 +01001354 if (options.defaultroute) {
1355 struct in_addr rm;
1356 rm.s_addr = 0;
Harald Welted12eab92017-08-02 19:49:47 +02001357 tun_addroute(tun, &rm, &addr.v4, &rm);
Harald Weltebed35df2011-11-02 13:06:18 +01001358 }
1359 if (options.ipup)
1360 tun_runscript(tun, options.ipup);
1361 }
jjako52c24142002-12-16 13:33:51 +00001362
Harald Weltebed35df2011-11-02 13:06:18 +01001363 ipset((struct iphash_t *)pdp->peer, &addr);
1364
1365 state = 2; /* Connected */
1366
1367 return 0;
jjako52c24142002-12-16 13:33:51 +00001368}
1369
Harald Weltebed35df2011-11-02 13:06:18 +01001370int delete_pdp_conf(struct pdp_t *pdp, int cause)
1371{
1372 printf("Received delete PDP context response. Cause value: %d\n",
1373 cause);
1374 return 0;
jjako52c24142002-12-16 13:33:51 +00001375}
1376
Harald Weltebed35df2011-11-02 13:06:18 +01001377int echo_conf(int recovery)
1378{
jjako91aaf222003-10-22 10:09:32 +00001379
Harald Weltebed35df2011-11-02 13:06:18 +01001380 if (recovery < 0) {
1381 printf("Echo Request timed out\n");
1382 if (echoversion == 1) {
1383 printf("Retrying with version 0\n");
1384 echoversion = 0;
1385 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1386 return 0;
1387 } else {
1388 state = 0;
1389 return EOF;
1390 }
1391 } else {
1392 printf("Received echo response\n");
1393 if (!options.contexts)
1394 state = 5;
1395 }
1396 return 0;
jjako52c24142002-12-16 13:33:51 +00001397}
1398
Harald Weltebed35df2011-11-02 13:06:18 +01001399int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1400{
1401 /* if (cause < 0) return 0; Some error occurred. We don't care */
1402 switch (type) {
1403 case GTP_ECHO_REQ:
1404 return echo_conf(cause);
1405 case GTP_CREATE_PDP_REQ:
1406 return create_pdp_conf(pdp, cbp, cause);
1407 case GTP_DELETE_PDP_REQ:
1408 if (cause != 128)
1409 return 0; /* Request not accepted. We don't care */
1410 return delete_pdp_conf(pdp, cause);
1411 default:
1412 return 0;
1413 }
jjako52c24142002-12-16 13:33:51 +00001414}
1415
Harald Weltebed35df2011-11-02 13:06:18 +01001416int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1417{
1418 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1419 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001420}
1421
1422int main(int argc, char **argv)
1423{
Harald Weltebed35df2011-11-02 13:06:18 +01001424 fd_set fds; /* For select() */
1425 struct timeval idleTime; /* How long to select() */
1426 struct pdp_t *pdp;
1427 int n;
1428 int starttime = time(NULL); /* Time program was started */
1429 int stoptime = 0; /* Time to exit */
1430 int pingtimeout = 0; /* Time to print ping statistics */
bjovana8f71eb2017-02-24 17:39:20 +01001431 int signal_received; /* If select() on fd_set is interrupted by signal. */
jjakoafb2a972003-01-29 21:04:13 +00001432
Harald Weltebed35df2011-11-02 13:06:18 +01001433 struct timezone tz; /* Used for calculating ping times */
1434 struct timeval tv;
1435 int diff;
jjako52c24142002-12-16 13:33:51 +00001436
bjovana8f71eb2017-02-24 17:39:20 +01001437 signal(SIGTERM, signal_handler);
1438 signal(SIGHUP, signal_handler);
1439 signal(SIGINT, signal_handler);
1440
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001441 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001442
Harald Weltebed35df2011-11-02 13:06:18 +01001443 /* Process options given in configuration file and command line */
1444 if (process_options(argc, argv))
1445 exit(1);
jjako52c24142002-12-16 13:33:51 +00001446
Harald Weltebed35df2011-11-02 13:06:18 +01001447 printf("\nInitialising GTP library\n");
1448 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001449 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001450 exit(1);
1451 }
1452 if (gsn->fd0 > maxfd)
1453 maxfd = gsn->fd0;
1454 if (gsn->fd1c > maxfd)
1455 maxfd = gsn->fd1c;
1456 if (gsn->fd1u > maxfd)
1457 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001458
Harald Weltebed35df2011-11-02 13:06:18 +01001459 gtp_set_cb_delete_context(gsn, delete_context);
1460 gtp_set_cb_conf(gsn, conf);
1461 if (options.createif)
1462 gtp_set_cb_data_ind(gsn, encaps_tun);
1463 else
1464 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001465
Harald Weltebed35df2011-11-02 13:06:18 +01001466 if (options.createif) {
1467 printf("Setting up interface\n");
1468 /* Create a tunnel interface */
1469 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001470 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001471 "Failed to create tun");
1472 exit(1);
1473 }
1474 tun_set_cb_ind(tun, cb_tun_ind);
1475 if (tun->fd > maxfd)
1476 maxfd = tun->fd;
1477 }
jjakoa7cd2492003-04-11 09:40:12 +00001478
Harald Weltebed35df2011-11-02 13:06:18 +01001479 if ((options.createif) && (options.net.s_addr)) {
Harald Welted12eab92017-08-02 19:49:47 +02001480 struct in_addr mask;
1481 mask.s_addr = options.prefixlen ? (0xFFFFFFFF >> (32 - options.prefixlen)) : 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001482 /* printf("Setting up interface and routing\n"); */
Harald Welted12eab92017-08-02 19:49:47 +02001483 tun_addaddr(tun, &options.netaddr, &options.destaddr, &mask);
Harald Weltebed35df2011-11-02 13:06:18 +01001484 if (options.defaultroute) {
1485 struct in_addr rm;
1486 rm.s_addr = 0;
1487 tun_addroute(tun, &rm, &options.destaddr, &rm);
1488 }
1489 if (options.ipup)
1490 tun_runscript(tun, options.ipup);
1491 }
jjakoa7cd2492003-04-11 09:40:12 +00001492
Harald Weltebed35df2011-11-02 13:06:18 +01001493 /* Initialise hash tables */
1494 memset(&iphash, 0, sizeof(iphash));
1495 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001496
Harald Weltebed35df2011-11-02 13:06:18 +01001497 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001498
Harald Weltebed35df2011-11-02 13:06:18 +01001499 /* See if anybody is there */
1500 printf("Sending off echo request\n");
1501 echoversion = options.gtpversion;
1502 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001503
Harald Weltebed35df2011-11-02 13:06:18 +01001504 for (n = 0; n < options.contexts; n++) {
1505 uint64_t myimsi;
1506 printf("Setting up PDP context #%d\n", n);
1507 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001508
Harald Weltebed35df2011-11-02 13:06:18 +01001509 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001510
Harald Weltebed35df2011-11-02 13:06:18 +01001511 /* Allocated here. */
1512 /* If create context failes we have to deallocate ourselves. */
1513 /* Otherwise it is deallocated by gtplib */
1514 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001515
Harald Weltebed35df2011-11-02 13:06:18 +01001516 pdp->peer = &iparr[n];
1517 pdp->ipif = tun; /* TODO */
1518 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001519
Harald Weltebed35df2011-11-02 13:06:18 +01001520 if (options.gtpversion == 0) {
1521 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001522 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001523 "QoS length too big");
1524 exit(1);
1525 } else {
1526 memcpy(pdp->qos_req0, options.qos.v,
1527 options.qos.l);
1528 }
1529 }
jjakoa7cd2492003-04-11 09:40:12 +00001530
Harald Weltebed35df2011-11-02 13:06:18 +01001531 pdp->qos_req.l = options.qos.l;
1532 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001533
Harald Weltebed35df2011-11-02 13:06:18 +01001534 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001535
Harald Weltebed35df2011-11-02 13:06:18 +01001536 pdp->rattype.l = options.rattype.l;
1537 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1538 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001539
Harald Weltebed35df2011-11-02 13:06:18 +01001540 pdp->userloc.l = options.userloc.l;
1541 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1542 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001543
Harald Weltebed35df2011-11-02 13:06:18 +01001544 pdp->rai.l = options.rai.l;
1545 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1546 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001547
Harald Weltebed35df2011-11-02 13:06:18 +01001548 pdp->mstz.l = options.mstz.l;
1549 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1550 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 pdp->imeisv.l = options.imeisv.l;
1553 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1554 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001555
Harald Weltebed35df2011-11-02 13:06:18 +01001556 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001557
Harald Weltebed35df2011-11-02 13:06:18 +01001558 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001559 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001560 "APN length too big");
1561 exit(1);
1562 } else {
1563 pdp->apn_use.l = options.apn.l;
1564 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1565 }
jjako193e8b12003-11-10 12:31:41 +00001566
Harald Weltebed35df2011-11-02 13:06:18 +01001567 pdp->gsnlc.l = sizeof(options.listen);
1568 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1569 pdp->gsnlu.l = sizeof(options.listen);
1570 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001571
Harald Weltebed35df2011-11-02 13:06:18 +01001572 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001573 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001574 "MSISDN length too big");
1575 exit(1);
1576 } else {
1577 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1578 }
jjakob62c3dd2004-05-27 18:51:55 +00001579
Harald Weltebed35df2011-11-02 13:06:18 +01001580 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
jjako52c24142002-12-16 13:33:51 +00001581
Harald Weltebed35df2011-11-02 13:06:18 +01001582 if (options.pco.l > sizeof(pdp->pco_req.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 "PCO length too big");
1585 exit(1);
1586 } else {
1587 pdp->pco_req.l = options.pco.l;
1588 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1589 }
jjako52c24142002-12-16 13:33:51 +00001590
Harald Weltebed35df2011-11-02 13:06:18 +01001591 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001592
Harald Weltebed35df2011-11-02 13:06:18 +01001593 pdp->hisaddr0 = options.remote;
1594 pdp->hisaddr1 = options.remote;
1595
1596 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1597 512 = Flat rate, 256 = Hot billing */
1598
1599 /* Create context */
1600 /* We send this of once. Retransmissions are handled by gtplib */
1601 gtp_create_context_req(gsn, pdp, &iparr[n]);
1602 }
1603
1604 state = 1; /* Enter wait_connection state */
1605
1606 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001607
jjako52c24142002-12-16 13:33:51 +00001608 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001609 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001610 /******************************************************************/
1611
Harald Weltebed35df2011-11-02 13:06:18 +01001612 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001613
Harald Weltebed35df2011-11-02 13:06:18 +01001614 /* Take down client after timeout after disconnect */
1615 if ((4 == state) && ((stoptime) <= time(NULL))) {
1616 state = 5;
1617 }
jjako7b8fad42003-07-07 14:37:42 +00001618
Harald Weltebed35df2011-11-02 13:06:18 +01001619 /* Take down client after timelimit timeout */
1620 if ((2 == state) && (options.timelimit) &&
1621 ((starttime + options.timelimit) <= time(NULL))) {
1622 state = 3;
1623 }
jjako7b8fad42003-07-07 14:37:42 +00001624
Harald Weltebed35df2011-11-02 13:06:18 +01001625 /* Take down client after ping timeout */
1626 if ((2 == state) && (pingtimeout)
1627 && (pingtimeout <= time(NULL))) {
1628 state = 3;
1629 }
jjako7b8fad42003-07-07 14:37:42 +00001630
Harald Weltebed35df2011-11-02 13:06:18 +01001631 /* Set pingtimeout for later disconnection */
1632 if (options.pingcount && ntransmitted >= options.pingcount) {
1633 pingtimeout = time(NULL) + 5; /* Extra seconds */
1634 }
jjako7b8fad42003-07-07 14:37:42 +00001635
Harald Weltebed35df2011-11-02 13:06:18 +01001636 /* Print statistics if no more ping packets are missing */
1637 if (ntransmitted && options.pingcount
1638 && nreceived >= options.pingcount) {
1639 ping_finish();
1640 if (!options.createif)
1641 state = 3;
1642 }
jjako7b8fad42003-07-07 14:37:42 +00001643
Harald Weltebed35df2011-11-02 13:06:18 +01001644 /* Send off disconnect */
1645 if (3 == state) {
1646 state = 4;
1647 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1648 for (n = 0; n < options.contexts; n++) {
1649 /* Delete context */
1650 printf("Disconnecting PDP context #%d\n", n);
1651 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1652 1);
1653 if ((options.pinghost.s_addr != 0)
1654 && ntransmitted)
1655 ping_finish();
1656 }
1657 }
jjako7b8fad42003-07-07 14:37:42 +00001658
Harald Weltebed35df2011-11-02 13:06:18 +01001659 /* Send of ping packets */
1660 diff = 0;
1661 while ((diff <= 0) &&
1662 /* Send off an ICMP ping packet */
1663 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1664 ((pingseq < options.pingcount)
1665 || (options.pingcount == 0))) {
1666 if (!pingseq)
1667 gettimeofday(&firstping, &tz); /* Set time of first ping */
1668 gettimeofday(&tv, &tz);
1669 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1670 if (diff <= 0) {
1671 if (options.debug)
1672 printf("Create_ping %d\n", diff);
1673 create_ping(gsn,
1674 iparr[pingseq %
1675 options.contexts].pdp,
1676 &options.pinghost, pingseq,
1677 options.pingsize);
1678 pingseq++;
1679 }
1680 }
jjako5da68452003-01-28 16:08:47 +00001681
Harald Weltebed35df2011-11-02 13:06:18 +01001682 FD_ZERO(&fds);
1683 if (tun)
1684 FD_SET(tun->fd, &fds);
1685 FD_SET(gsn->fd0, &fds);
1686 FD_SET(gsn->fd1c, &fds);
1687 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001688
Harald Weltebed35df2011-11-02 13:06:18 +01001689 gtp_retranstimeout(gsn, &idleTime);
1690 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001691
Harald Weltebed35df2011-11-02 13:06:18 +01001692 if (options.debug)
1693 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1694 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001695
bjovana8f71eb2017-02-24 17:39:20 +01001696 signal_received = 0;
Harald Weltebed35df2011-11-02 13:06:18 +01001697 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1698 case -1:
bjovana8f71eb2017-02-24 17:39:20 +01001699 if (errno == EINTR)
1700 signal_received = 1;
1701 else
1702 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1703 "Select returned -1");
Harald Weltebed35df2011-11-02 13:06:18 +01001704 break;
1705 case 0:
1706 gtp_retrans(gsn); /* Only retransmit if nothing else */
1707 break;
1708 default:
1709 break;
1710 }
1711
bjovana8f71eb2017-02-24 17:39:20 +01001712 if (!signal_received) {
1713
1714 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1715 SYS_ERR(DSGSN, LOGL_ERROR, 0,
1716 "TUN decaps failed");
1717 }
1718
1719 if (FD_ISSET(gsn->fd0, &fds))
1720 gtp_decaps0(gsn);
1721
1722 if (FD_ISSET(gsn->fd1c, &fds))
1723 gtp_decaps1c(gsn);
1724
1725 if (FD_ISSET(gsn->fd1u, &fds))
1726 gtp_decaps1u(gsn);
1727
Harald Weltebed35df2011-11-02 13:06:18 +01001728 }
Harald Weltebed35df2011-11-02 13:06:18 +01001729 }
1730
1731 gtp_free(gsn); /* Clean up the gsn instance */
1732
1733 if (options.createif)
1734 tun_free(tun);
1735
1736 if (0 == state)
1737 exit(1); /* Indicate error */
1738
1739 return 0;
jjako52c24142002-12-16 13:33:51 +00001740}