blob: a4d6461c8ce4485f10d7bb9f2bc327af2f3079b5 [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 Mondru AB.
jjako52c24142002-12-16 13:33:51 +00004 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/*
13 * sgsnemu.c
14 *
15 */
16
jjako52c24142002-12-16 13:33:51 +000017#ifdef __linux__
Harald Weltebed35df2011-11-02 13:06:18 +010018#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000019#endif
20
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +010021#include <osmocom/core/application.h>
22
jjako52c24142002-12-16 13:33:51 +000023#include <ctype.h>
24#include <netdb.h>
25#include <signal.h>
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <netinet/in.h>
32#include <arpa/inet.h>
33#include <sys/wait.h>
34#include <sys/stat.h>
35#include <unistd.h>
36#include <sys/socket.h>
37#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000038#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000039#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000040#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000041#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000042#include <resolv.h>
43#include <time.h>
44
jjakoff9985c2004-01-16 11:05:22 +000045#include "config.h"
Emmanuel Bretelle2a103682010-09-07 17:01:20 +020046#include "../lib/tun.h"
47#include "../lib/ippool.h"
48#include "../lib/syserr.h"
jjako52c24142002-12-16 13:33:51 +000049#include "../gtp/pdp.h"
50#include "../gtp/gtp.h"
51#include "cmdline.h"
52
Harald Weltebed35df2011-11-02 13:06:18 +010053#define IPADDRLEN 256 /* Character length of addresses */
54#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000055
jjakoa7cd2492003-04-11 09:40:12 +000056/* HASH tables for IP address allocation */
57struct iphash_t {
Harald Weltebed35df2011-11-02 13:06:18 +010058 uint8_t inuse; /* 0=free. 1=used by somebody */
59 struct iphash_t *ipnext;
60 struct pdp_t *pdp;
61 struct in_addr addr;
jjakoa7cd2492003-04-11 09:40:12 +000062};
63struct iphash_t iparr[MAXCONTEXTS];
64struct iphash_t *iphash[MAXCONTEXTS];
65
66/* State variable used for ping */
67/* 0: Idle */
68/* 1: Wait_connect */
69/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000070/* 3: Done */
71/* 4: Wait_disconnect */
72/* 5: Disconnected */
jjako581c9f02003-10-22 11:28:20 +000073int state = 0;
jjako52c24142002-12-16 13:33:51 +000074
Harald Weltebed35df2011-11-02 13:06:18 +010075struct gsn_t *gsn = NULL; /* GSN instance */
76struct tun_t *tun = NULL; /* TUN instance */
77int maxfd = 0; /* For select() */
78int echoversion = 1; /* First try this version */
jjako52c24142002-12-16 13:33:51 +000079
jjakoa7cd2492003-04-11 09:40:12 +000080/* Struct with local versions of gengetopt options */
81struct {
Harald Weltebed35df2011-11-02 13:06:18 +010082 int debug; /* Print debug messages */
83 int createif; /* Create local network interface */
84 struct in_addr netaddr, destaddr, net, mask; /* Network interface */
85 char *ipup, *ipdown; /* Filename of scripts */
86 int defaultroute; /* Set up default route */
87 struct in_addr pinghost; /* Remote ping host */
88 int pingrate;
89 int pingsize;
90 int pingcount;
91 int pingquiet;
92 struct in_addr listen;
93 struct in_addr remote;
94 struct in_addr dns;
95 int contexts; /* Number of contexts to create */
96 int timelimit; /* Number of seconds to be connected */
97 char *statedir;
98 uint64_t imsi;
99 uint8_t nsapi;
100 int gtpversion;
101 struct ul255_t pco;
102 struct ul255_t qos;
103 uint16_t cch;
104 struct ul255_t apn;
105 uint8_t selmode;
106 struct ul255_t rattype;
107 int rattype_given;
108 struct ul255_t userloc;
109 int userloc_given;
110 struct ul255_t rai;
111 int rai_given;
112 struct ul255_t mstz;
113 int mstz_given;
114 struct ul255_t imeisv;
115 int imeisv_given;
116 struct ul16_t msisdn;
117 int norecovery_given;
jjakoa7cd2492003-04-11 09:40:12 +0000118} options;
jjako52c24142002-12-16 13:33:51 +0000119
jjako5da68452003-01-28 16:08:47 +0000120/* Definitions to use for PING. Most of the ping code was derived from */
121/* the original ping program by Mike Muuss */
122
123/* IP header and ICMP echo header */
124#define CREATEPING_MAX 2048
125#define CREATEPING_IP 20
126#define CREATEPING_ICMP 8
127
128struct ip_ping {
Harald Weltebed35df2011-11-02 13:06:18 +0100129 uint8_t ipver; /* Type and header length */
130 uint8_t tos; /* Type of Service */
131 uint16_t length; /* Total length */
132 uint16_t fragid; /* Identifier */
133 uint16_t offset; /* Flags and fragment offset */
134 uint8_t ttl; /* Time to live */
135 uint8_t protocol; /* Protocol */
136 uint16_t ipcheck; /* Header checksum */
137 uint32_t src; /* Source address */
138 uint32_t dst; /* Destination */
139 uint8_t type; /* Type and header length */
140 uint8_t code; /* Code */
141 uint16_t checksum; /* Header checksum */
142 uint16_t ident; /* Identifier */
143 uint16_t seq; /* Sequence number */
144 uint8_t data[CREATEPING_MAX]; /* Data */
145} __attribute__ ((packed));
jjako5da68452003-01-28 16:08:47 +0000146
147/* Statistical values for ping */
148int nreceived = 0;
149int ntreceived = 0;
150int ntransmitted = 0;
151int tmin = 999999999;
152int tmax = 0;
153int tsum = 0;
Harald Weltebed35df2011-11-02 13:06:18 +0100154int pingseq = 0; /* Ping sequence counter */
jjakoafb2a972003-01-29 21:04:13 +0000155struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000156
Harald Weltebed35df2011-11-02 13:06:18 +0100157int ipset(struct iphash_t *ipaddr, struct in_addr *addr)
158{
159 int hash = ippool_hash4(addr) % MAXCONTEXTS;
160 struct iphash_t *h;
161 struct iphash_t *prev = NULL;
162 ipaddr->ipnext = NULL;
163 ipaddr->addr.s_addr = addr->s_addr;
164 for (h = iphash[hash]; h; h = h->ipnext)
165 prev = h;
166 if (!prev)
167 iphash[hash] = ipaddr;
168 else
169 prev->ipnext = ipaddr;
170 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000171}
172
Harald Weltebed35df2011-11-02 13:06:18 +0100173int ipdel(struct iphash_t *ipaddr)
174{
175 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
176 struct iphash_t *h;
177 struct iphash_t *prev = NULL;
178 for (h = iphash[hash]; h; h = h->ipnext) {
179 if (h == ipaddr) {
180 if (!prev)
181 iphash[hash] = h->ipnext;
182 else
183 prev->ipnext = h->ipnext;
184 return 0;
185 }
186 prev = h;
187 }
188 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000189}
190
Harald Weltebed35df2011-11-02 13:06:18 +0100191int ipget(struct iphash_t **ipaddr, struct in_addr *addr)
192{
193 int hash = ippool_hash4(addr) % MAXCONTEXTS;
194 struct iphash_t *h;
195 for (h = iphash[hash]; h; h = h->ipnext) {
196 if ((h->addr.s_addr == addr->s_addr)) {
197 *ipaddr = h;
198 return 0;
199 }
200 }
201 return EOF; /* End of linked list and not found */
jjakoa7cd2492003-04-11 09:40:12 +0000202}
203
jjakoa7cd2492003-04-11 09:40:12 +0000204/* Used to write process ID to file. Assume someone else will delete */
Harald Weltebed35df2011-11-02 13:06:18 +0100205void log_pid(char *pidfile)
206{
207 FILE *file;
208 mode_t oldmask;
209
210 oldmask = umask(022);
211 file = fopen(pidfile, "w");
212 umask(oldmask);
213 if (!file)
214 return;
215 fprintf(file, "%d\n", (int)getpid());
216 fclose(file);
jjakoa7cd2492003-04-11 09:40:12 +0000217}
218
Harald Weltebed35df2011-11-02 13:06:18 +0100219int process_options(int argc, char **argv)
220{
221 /* gengeopt declarations */
222 struct gengetopt_args_info args_info;
jjakoa7cd2492003-04-11 09:40:12 +0000223
Harald Weltebed35df2011-11-02 13:06:18 +0100224 struct hostent *host;
225 unsigned int n;
226 uint16_t i;
227 uint8_t a;
228 uint8_t b;
229 char *tmp;
230 char *pch;
231 char *type;
232 char *mcc;
233 char *mnc;
Andreas Schultz10abfba2015-11-13 15:57:37 +0100234 char *tok, *apn;
Harald Weltebed35df2011-11-02 13:06:18 +0100235 char *lac;
236 int lac_d;
237 char *rest;
238 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
239 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
240 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
241 int sign;
242 int nbquarters;
243 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000244
Harald Weltebed35df2011-11-02 13:06:18 +0100245 if (cmdline_parser(argc, argv, &args_info) != 0)
246 return -1;
247 if (args_info.debug_flag) {
248 if (args_info.remote_arg)
249 printf("remote: %s\n", args_info.remote_arg);
250 if (args_info.listen_arg)
251 printf("listen: %s\n", args_info.listen_arg);
252 if (args_info.conf_arg)
253 printf("conf: %s\n", args_info.conf_arg);
254 printf("debug: %d\n", args_info.debug_flag);
255 if (args_info.imsi_arg)
256 printf("imsi: %s\n", args_info.imsi_arg);
257 printf("qos: %#08x\n", args_info.qos_arg);
258 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
259 printf("qose2: %#04x\n", args_info.qose2_arg);
260 printf("qose3: %#06x\n", args_info.qose3_arg);
261 printf("qose4: %#06x\n", args_info.qose4_arg);
262 printf("charging: %#04x\n", args_info.charging_arg);
263 if (args_info.apn_arg)
264 printf("apn: %s\n", args_info.apn_arg);
265 if (args_info.msisdn_arg)
266 printf("msisdn: %s\n", args_info.msisdn_arg);
267 if (args_info.uid_arg)
268 printf("uid: %s\n", args_info.uid_arg);
269 if (args_info.pwd_arg)
270 printf("pwd: %s\n", args_info.pwd_arg);
271 if (args_info.pidfile_arg)
272 printf("pidfile: %s\n", args_info.pidfile_arg);
273 if (args_info.statedir_arg)
274 printf("statedir: %s\n", args_info.statedir_arg);
275 if (args_info.dns_arg)
276 printf("dns: %s\n", args_info.dns_arg);
277 printf("contexts: %d\n", args_info.contexts_arg);
278 printf("timelimit: %d\n", args_info.timelimit_arg);
279 printf("createif: %d\n", args_info.createif_flag);
280 if (args_info.ipup_arg)
281 printf("ipup: %s\n", args_info.ipup_arg);
282 if (args_info.ipdown_arg)
283 printf("ipdown: %s\n", args_info.ipdown_arg);
284 printf("defaultroute: %d\n", args_info.defaultroute_flag);
285 if (args_info.pinghost_arg)
286 printf("pinghost: %s\n", args_info.pinghost_arg);
287 printf("pingrate: %d\n", args_info.pingrate_arg);
288 printf("pingsize: %d\n", args_info.pingsize_arg);
289 printf("pingcount: %d\n", args_info.pingcount_arg);
290 printf("pingquiet: %d\n", args_info.pingquiet_flag);
291 printf("norecovery: %d\n", args_info.norecovery_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100292 }
jjakoa7cd2492003-04-11 09:40:12 +0000293
Harald Weltebed35df2011-11-02 13:06:18 +0100294 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000295
Harald Weltebed35df2011-11-02 13:06:18 +0100296 if (args_info.conf_arg) {
297 if (cmdline_parser_configfile
298 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
299 return -1;
300 if (args_info.debug_flag) {
301 printf("cmdline_parser_configfile\n");
302 if (args_info.remote_arg)
303 printf("remote: %s\n", args_info.remote_arg);
304 if (args_info.listen_arg)
305 printf("listen: %s\n", args_info.listen_arg);
306 if (args_info.conf_arg)
307 printf("conf: %s\n", args_info.conf_arg);
308 printf("debug: %d\n", args_info.debug_flag);
309 if (args_info.imsi_arg)
310 printf("imsi: %s\n", args_info.imsi_arg);
311 printf("qos: %#08x\n", args_info.qos_arg);
312 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
313 printf("qose2: %#04x\n", args_info.qose2_arg);
314 printf("qose3: %#06x\n", args_info.qose3_arg);
315 printf("qose4: %#06x\n", args_info.qose4_arg);
316 printf("charging: %#04x\n", args_info.charging_arg);
317 if (args_info.apn_arg)
318 printf("apn: %s\n", args_info.apn_arg);
319 if (args_info.msisdn_arg)
320 printf("msisdn: %s\n", args_info.msisdn_arg);
321 if (args_info.uid_arg)
322 printf("uid: %s\n", args_info.uid_arg);
323 if (args_info.pwd_arg)
324 printf("pwd: %s\n", args_info.pwd_arg);
325 if (args_info.pidfile_arg)
326 printf("pidfile: %s\n", args_info.pidfile_arg);
327 if (args_info.statedir_arg)
328 printf("statedir: %s\n",
329 args_info.statedir_arg);
330 if (args_info.dns_arg)
331 printf("dns: %s\n", args_info.dns_arg);
332 printf("contexts: %d\n", args_info.contexts_arg);
333 printf("timelimit: %d\n", args_info.timelimit_arg);
334 printf("createif: %d\n", args_info.createif_flag);
335 if (args_info.ipup_arg)
336 printf("ipup: %s\n", args_info.ipup_arg);
337 if (args_info.ipdown_arg)
338 printf("ipdown: %s\n", args_info.ipdown_arg);
339 printf("defaultroute: %d\n",
340 args_info.defaultroute_flag);
341 if (args_info.pinghost_arg)
342 printf("pinghost: %s\n",
343 args_info.pinghost_arg);
344 printf("pingrate: %d\n", args_info.pingrate_arg);
345 printf("pingsize: %d\n", args_info.pingsize_arg);
346 printf("pingcount: %d\n", args_info.pingcount_arg);
347 printf("pingquiet: %d\n", args_info.pingquiet_flag);
348 printf("norecovery: %d\n", args_info.norecovery_flag);
349 }
350 }
jjako193e8b12003-11-10 12:31:41 +0000351
Harald Weltebed35df2011-11-02 13:06:18 +0100352 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000353
Harald Weltebed35df2011-11-02 13:06:18 +0100354 /* foreground */
355 /* If fg flag not given run as a daemon */
356 /* Do not allow sgsnemu to run as deamon
357 if (!args_info.fg_flag)
358 {
359 closelog();
360 freopen("/dev/null", "w", stdout);
361 freopen("/dev/null", "w", stderr);
362 freopen("/dev/null", "r", stdin);
363 daemon(0, 0);
364 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
365 } */
jjako1a51df72004-07-20 08:30:21 +0000366
Harald Weltebed35df2011-11-02 13:06:18 +0100367 /* debug */
368 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000369
Harald Weltebed35df2011-11-02 13:06:18 +0100370 /* pidfile */
371 /* This has to be done after we have our final pid */
372 if (args_info.pidfile_arg) {
373 log_pid(args_info.pidfile_arg);
374 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200375
Harald Weltebed35df2011-11-02 13:06:18 +0100376 /* dns */
377 /* If no dns option is given use system default */
378 /* Do hostname lookup to translate hostname to IP address */
379 printf("\n");
380 if (args_info.dns_arg) {
381 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100382 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100383 "Invalid DNS address: %s!", args_info.dns_arg);
384 return -1;
385 } else {
386 memcpy(&options.dns.s_addr, host->h_addr,
387 host->h_length);
388 _res.nscount = 1;
389 _res.nsaddr_list[0].sin_addr = options.dns;
390 printf("Using DNS server: %s (%s)\n",
391 args_info.dns_arg, inet_ntoa(options.dns));
392 }
393 } else {
394 options.dns.s_addr = 0;
395 printf("Using default DNS server\n");
396 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200397
Harald Weltebed35df2011-11-02 13:06:18 +0100398 /* listen */
399 /* If no listen option is specified listen to any local port */
400 /* Do hostname lookup to translate hostname to IP address */
401 if (args_info.listen_arg) {
402 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100403 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100404 "Invalid listening address: %s!",
405 args_info.listen_arg);
406 return -1;
407 } else {
408 memcpy(&options.listen.s_addr, host->h_addr,
409 host->h_length);
410 printf("Local IP address is: %s (%s)\n",
411 args_info.listen_arg, inet_ntoa(options.listen));
412 }
413 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100414 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100415 "Listening address must be specified: %s!",
416 args_info.listen_arg);
417 return -1;
418 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200419
Harald Weltebed35df2011-11-02 13:06:18 +0100420 /* remote */
421 /* If no remote option is specified terminate */
422 /* Do hostname lookup to translate hostname to IP address */
423 if (args_info.remote_arg) {
424 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100425 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100426 "Invalid remote address: %s!",
427 args_info.remote_arg);
428 return -1;
429 } else {
430 memcpy(&options.remote.s_addr, host->h_addr,
431 host->h_length);
432 printf("Remote IP address is: %s (%s)\n",
433 args_info.remote_arg, inet_ntoa(options.remote));
434 }
435 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100436 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100437 "No remote address given!");
438 return -1;
439 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200440
Harald Weltebed35df2011-11-02 13:06:18 +0100441 /* imsi */
442 if (strlen(args_info.imsi_arg) != 15) {
443 printf("Invalid IMSI\n");
444 return -1;
445 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200446
Harald Weltebed35df2011-11-02 13:06:18 +0100447 options.imsi = 0xf000000000000000ull;
448 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
449 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
450 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
451 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
452 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
453 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
454 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
455 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
456 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
457 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
458 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
459 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
460 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
461 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
462 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200463
Harald Weltebed35df2011-11-02 13:06:18 +0100464 printf("IMSI is: %s (%#08llx)\n",
465 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200466
Harald Weltebed35df2011-11-02 13:06:18 +0100467 /* nsapi */
468 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
469 printf("Invalid NSAPI\n");
470 return -1;
471 }
472 options.nsapi = args_info.nsapi_arg;
473 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200474
Harald Weltebed35df2011-11-02 13:06:18 +0100475 /* qos */
476 options.qos.l = 4;
477 options.qos.v[3] = (args_info.qos_arg) & 0xff;
478 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
479 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
480 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
481 /* Extensions according to 3GPP TS 24.008 */
482 if (args_info.qose1_given == 1) {
483 options.qos.l = 12;
484 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
485 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
486 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
487 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
488 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
489 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
490 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
491 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
492 if (args_info.qose2_given == 1) {
493 options.qos.l = 13;
494 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
495 if (args_info.qose3_given == 1) {
496 options.qos.l = 15;
497 options.qos.v[14] =
498 (args_info.qose3_arg) & 0xff;
499 options.qos.v[13] =
500 ((args_info.qose3_arg) >> 8) & 0xff;
501 if (args_info.qose4_given == 1) {
502 options.qos.l = 17;
503 options.qos.v[16] =
504 (args_info.qose4_arg) & 0xff;
505 options.qos.v[15] =
506 ((args_info.qose4_arg) >> 8) & 0xff;
507 }
508 }
509 }
510 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200511
Harald Weltebed35df2011-11-02 13:06:18 +0100512 /* charging */
513 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200514
Harald Weltebed35df2011-11-02 13:06:18 +0100515 /* contexts */
516 if (args_info.contexts_arg > MAXCONTEXTS) {
517 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
518 return -1;
519 }
520 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200521
Harald Weltebed35df2011-11-02 13:06:18 +0100522 /* Timelimit */
523 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200524
Harald Weltebed35df2011-11-02 13:06:18 +0100525 /* gtpversion */
526 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
527 printf("Invalid GTP version\n");
528 return -1;
529 }
530 options.gtpversion = args_info.gtpversion_arg;
531 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200532
Harald Weltebed35df2011-11-02 13:06:18 +0100533 /* apn */
534 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
535 printf("Invalid APN\n");
536 return -1;
537 }
Andreas Schultz10abfba2015-11-13 15:57:37 +0100538 options.apn.l = strlen(args_info.apn_arg) + 1;
539
540 apn = (char *)options.apn.v;
541 for (tok = strtok(args_info.apn_arg, ".");
542 tok != NULL;
543 tok = strtok(NULL, ".")) {
544 size_t len = strlen(tok);
545
546 *apn++ = (char)len;
547 strncpy(apn, tok, len);
548 apn += len;
549 }
550
Harald Weltebed35df2011-11-02 13:06:18 +0100551 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200552
Harald Weltebed35df2011-11-02 13:06:18 +0100553 /* selmode */
554 options.selmode = args_info.selmode_arg;
555 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200556
Harald Weltebed35df2011-11-02 13:06:18 +0100557 /* rattype */
558 if (args_info.rattype_given == 1) {
559 options.rattype_given = 1;
560 options.rattype.l = strlen(args_info.rattype_arg);
561 options.rattype.v[0] = atoi(args_info.rattype_arg);
562 printf("Using RAT Type: %s\n", args_info.rattype_arg);
563 }
Harald Welte41af5692011-10-07 18:42:34 +0200564
Harald Weltebed35df2011-11-02 13:06:18 +0100565 /* userloc */
566 if (args_info.userloc_given == 1) {
567 printf("Using User Location Information: %s\n",
568 args_info.userloc_arg);
569 tmp = args_info.userloc_arg;
570 n = 0;
571 pch = strtok(tmp, ".");
572 while (pch != NULL) {
573 userloc_el[n] = pch;
574 pch = strtok(NULL, ".");
575 n++;
576 }
Harald Welte41af5692011-10-07 18:42:34 +0200577
Harald Weltebed35df2011-11-02 13:06:18 +0100578 options.userloc_given = 1;
579 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200580
Harald Weltebed35df2011-11-02 13:06:18 +0100581 /* 3GPP Geographic Location Type t0 / t1 / t2 */
582 type = userloc_el[0];
583 printf("->type : %c\n", type[0]);
584 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
585 printf("Invalid type \n");
586 return -1;
587 }
588 /* options.userloc.v[0] = 0x00 */
589 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200590
Harald Weltebed35df2011-11-02 13:06:18 +0100591 /* MCC */
592 mcc = userloc_el[1];
593 printf("->mcc : %s\n", mcc);
594 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200595 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100596 return -1;
597 }
Harald Welte41af5692011-10-07 18:42:34 +0200598
Harald Weltebed35df2011-11-02 13:06:18 +0100599 /* MNC */
600 mnc = userloc_el[2];
601 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200602
Harald Weltebed35df2011-11-02 13:06:18 +0100603 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
604 /* options.userloc.v[1] = 0x52 */
605 a = (uint8_t) (mcc[0] - 48);
606 b = (uint8_t) (mcc[1] - 48);
607 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200608
Harald Weltebed35df2011-11-02 13:06:18 +0100609 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
610 /* options.userloc.v[2] = 0xf0 */
611 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200612
Harald Weltebed35df2011-11-02 13:06:18 +0100613 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200614 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100615 return -1;
616 }
617 if (strlen(mnc) == 2) {
618 b = 15;
619 }
620 if (strlen(mnc) == 3) {
621 b = (uint8_t) (mnc[2] - 48);
622 }
623 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200624
Harald Weltebed35df2011-11-02 13:06:18 +0100625 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
626 /* options.userloc.v[3] = 0x99 */
627 a = (uint8_t) (mnc[0] - 48);
628 b = (uint8_t) (mnc[1] - 48);
629 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200630
Harald Weltebed35df2011-11-02 13:06:18 +0100631 /* LAC */
632 lac = userloc_el[3];
633 /*options.userloc.v[4] = 0x12 ; */
634 /*options.userloc.v[5] = 0x10 ; */
635 printf("->LAC: %s\n", lac);
636 lac_d = atoi(lac);
637 if (lac_d > 65535 || lac_d < 1) {
638 printf("Invalid LAC\n");
639 return -1;
640 }
641 i = lac_d >> 8;
642 options.userloc.v[4] = i; /* octet 8 - LAC */
643 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200644
Harald Weltebed35df2011-11-02 13:06:18 +0100645 /* CI/SAC/RAC */
646 rest = userloc_el[4];
647 printf("->CI/SAC/RAC : %s\n", rest);
648 lac_d = atoi(rest);
649 if (lac_d > 65535 || lac_d < 1) {
650 printf("Invalid CI/SAC/RAC\n");
651 return -1;
652 }
653 /*options.userloc.v[6] = 0x04 ; */
654 /*options.userloc.v[7] = 0xb7 ; */
655 i = lac_d >> 8;
656 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
657 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
658 }
jjakoa7cd2492003-04-11 09:40:12 +0000659
Harald Weltebed35df2011-11-02 13:06:18 +0100660 /* RAI */
661 if (args_info.rai_given == 1) {
662 printf("Using RAI: %s\n", args_info.rai_arg);
663 tmp = args_info.rai_arg;
664 n = 0;
665 pch = strtok(tmp, ".");
666 while (pch != NULL) {
667 rai_el[n] = pch;
668 pch = strtok(NULL, ".");
669 n++;
670 }
jjakoa7cd2492003-04-11 09:40:12 +0000671
Harald Weltebed35df2011-11-02 13:06:18 +0100672 options.rai_given = 1;
673 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000674
Harald Weltebed35df2011-11-02 13:06:18 +0100675 /* MCC */
676 mcc = rai_el[0];
677 printf("->mcc : %s\n", mcc);
678 if (strlen(mcc) != 3) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200679 printf("Invalid MCC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100680 return -1;
681 }
682
683 /* MNC */
684 mnc = rai_el[1];
685 printf("->mnc : %s\n", mnc);
686
687 a = (uint8_t) (mcc[0] - 48);
688 b = (uint8_t) (mcc[1] - 48);
689 options.rai.v[0] = 16 * b + a;
690
691 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
692 a = (uint8_t) (mcc[2] - 48);
693
694 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
Ruben Undheimcc077ae2016-05-24 23:31:47 +0200695 printf("Invalid MNC length\n");
Harald Weltebed35df2011-11-02 13:06:18 +0100696 return -1;
697 }
698 if (strlen(mnc) == 2) {
699 b = 15;
700 }
701 if (strlen(mnc) == 3) {
702 b = (uint8_t) (mnc[2] - 48);
703 }
704 options.rai.v[1] = 16 * b + a;
705
706 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
707 a = (uint8_t) (mnc[0] - 48);
708 b = (uint8_t) (mnc[1] - 48);
709 options.rai.v[2] = 16 * b + a;
710
711 /* LAC */
712 lac = rai_el[2];
713 printf("->LAC: %s\n", lac);
714 lac_d = atoi(lac);
715 if (lac_d > 65535 || lac_d < 1) {
716 printf("Invalid LAC\n");
717 return -1;
718 }
719 i = lac_d >> 8;
720 options.rai.v[3] = i; /* octet 5 - LAC */
721 options.rai.v[4] = lac_d; /* octet 6 - LAC */
722
723 /* RAC */
724 rest = rai_el[3];
725 printf("->RAC : %s\n", rest);
726 lac_d = atoi(rest);
727 if (lac_d > 255 || lac_d < 1) {
728 printf("Invalid RAC\n");
729 return -1;
730 }
731 options.rai.v[5] = lac_d; /* octet 7 - RAC */
732 }
733
734 /* mstz */
735 if (args_info.mstz_given == 1) {
736 options.mstz_given = 1;
737 options.mstz.l = 2;
738
739 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
740 tmp = args_info.mstz_arg;
741 n = 0;
742 pch = strtok(tmp, ".");
743 while (pch != NULL) {
744 mstz_el[n] = pch;
745 pch = strtok(NULL, ".");
746 n++;
747 }
748
749 /* sign */
750 sign = atoi(mstz_el[0]);
751 printf("->Sign (0=+ / 1=-): %d\n", sign);
752 if (sign != 0 && sign != 1) {
753 printf("Invalid Sign \n");
754 return -1;
755 }
756 /* nbquarters */
757 nbquarters = atoi(mstz_el[1]);
758 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
759 if (nbquarters < 0 || nbquarters > 79) {
760 printf("Invalid Number of Quarters \n");
761 return -1;
762 }
763 /* DST */
764 DST = atoi(mstz_el[2]);
765 printf("->Daylight Saving Time Adjustment : %d\n", DST);
766 if (DST < 0 || DST > 3) {
767 printf("Invalid DST Adjustment \n");
768 return -1;
769 }
770 /* 12345678
771 bits 123 = unit of # of quarters of an hour
772 bits 678 = # of quarters of an hour / 10
773 bit 5 = sign
774 */
775 i = nbquarters % 10;
776 i = i << 4;
777 i = i + nbquarters / 10 + 8 * sign;
778 /* options.mstz.v[0] = 0x69 ; */
779 /* options.mstz.v[1] = 0x01 ; */
780 options.mstz.v[0] = i;
781 options.mstz.v[1] = DST;
782 n = (i & 0x08) ? '-' : '+';
783 printf
784 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
785 n, nbquarters / 4, nbquarters % 4 * 15);
786 }
787
788 /* imeisv */
789 if (args_info.imeisv_given == 1) {
790 options.imeisv_given = 1;
791 if (strlen(args_info.imeisv_arg) != 16) {
792 printf("Invalid IMEI(SV)\n");
793 return -1;
794 }
795 options.imeisv.l = 8;
796 for (n = 0; n < 8; n++) {
797 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
798 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
799 options.imeisv.v[n] = 16 * b + a;
800 }
801 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
802 }
803
804 /* msisdn */
805 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
806 printf("Invalid MSISDN\n");
807 return -1;
808 }
809 options.msisdn.l = 1;
810 options.msisdn.v[0] = 0x91; /* International format */
811 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
812 if ((n % 2) == 0) {
813 options.msisdn.v[((int)n / 2) + 1] =
814 args_info.msisdn_arg[n] - 48 + 0xf0;
815 options.msisdn.l += 1;
816 } else {
817 options.msisdn.v[((int)n / 2) + 1] =
818 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
819 (args_info.msisdn_arg[n] - 48) * 16;
820 }
821 }
822 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
823
824 /* UID and PWD */
825 /* Might need to also insert stuff like DNS etc. */
826 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
827 (sizeof(options.pco.v) - 1)) {
828 printf("invalid UID and PWD\n");
829 return -1;
830 }
831 options.pco.l =
832 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
833 options.pco.v[0] = 0x80; /* PPP */
834 options.pco.v[1] = 0xc0; /* PAP */
835 options.pco.v[2] = 0x23;
836 options.pco.v[3] =
837 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
838 options.pco.v[4] = 0x01; /* Authenticate request */
839 options.pco.v[5] = 0x01;
840 options.pco.v[6] = 0x00; /* MSB of length */
841 options.pco.v[7] =
842 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
843 options.pco.v[8] = strlen(args_info.uid_arg);
844 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
845 options.pco.v[9 + strlen(args_info.uid_arg)] =
846 strlen(args_info.pwd_arg);
847 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
848 args_info.pwd_arg, strlen(args_info.pwd_arg));
849
850 /* createif */
851 options.createif = args_info.createif_flag;
852
853 /* net */
854 /* Store net as in_addr net and mask */
855 if (args_info.net_arg) {
856 if (ippool_aton
857 (&options.net, &options.mask, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100858 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100859 "Invalid network address: %s!",
860 args_info.net_arg);
861 exit(1);
862 }
jjakoc6762cf2004-04-28 14:52:58 +0000863#if defined (__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100864 options.netaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
865 options.destaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
jjakoc6762cf2004-04-28 14:52:58 +0000866#else
Harald Weltebed35df2011-11-02 13:06:18 +0100867 options.netaddr.s_addr = options.net.s_addr;
868 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000869#endif
870
Harald Weltebed35df2011-11-02 13:06:18 +0100871 } else {
872 options.net.s_addr = 0;
873 options.mask.s_addr = 0;
874 options.netaddr.s_addr = 0;
875 options.destaddr.s_addr = 0;
876 }
jjako193e8b12003-11-10 12:31:41 +0000877
Harald Weltebed35df2011-11-02 13:06:18 +0100878 /* ipup */
879 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000880
Harald Weltebed35df2011-11-02 13:06:18 +0100881 /* ipdown */
882 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000883
Harald Weltebed35df2011-11-02 13:06:18 +0100884 /* statedir */
885 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000886
Harald Weltebed35df2011-11-02 13:06:18 +0100887 /* defaultroute */
888 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000889
Harald Weltebed35df2011-11-02 13:06:18 +0100890 /* pinghost */
891 /* Store ping host as in_addr */
892 if (args_info.pinghost_arg) {
893 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100894 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100895 "Invalid ping host: %s!",
896 args_info.pinghost_arg);
897 return -1;
898 } else {
899 memcpy(&options.pinghost.s_addr, host->h_addr,
900 host->h_length);
901 printf("Using ping host: %s (%s)\n",
902 args_info.pinghost_arg,
903 inet_ntoa(options.pinghost));
904 }
905 }
jjakoa7cd2492003-04-11 09:40:12 +0000906
Harald Weltebed35df2011-11-02 13:06:18 +0100907 /* Other ping parameters */
908 options.pingrate = args_info.pingrate_arg;
909 options.pingsize = args_info.pingsize_arg;
910 options.pingcount = args_info.pingcount_arg;
911 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000912
Harald Weltebed35df2011-11-02 13:06:18 +0100913 /* norecovery */
914 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000915
Harald Weltebed35df2011-11-02 13:06:18 +0100916 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000917
918}
919
Harald Weltebed35df2011-11-02 13:06:18 +0100920int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
921{
922 unsigned int i;
923 printf("The packet looks like this:\n");
924 for (i = 0; i < len; i++) {
925 printf("%02x ", (unsigned char)*(char *)(pack + i));
926 if (!((i + 1) % 16))
927 printf("\n");
928 };
929 printf("\n");
930 return 0;
jjako52c24142002-12-16 13:33:51 +0000931}
932
Harald Weltebed35df2011-11-02 13:06:18 +0100933char *print_ipprot(int t)
934{
935 switch (t) {
936 case 1:
937 return "ICMP";
938 case 6:
939 return "TCP";
940 case 17:
941 return "UDP";
942 default:
943 return "Unknown";
944 };
jjako5da68452003-01-28 16:08:47 +0000945}
946
Harald Weltebed35df2011-11-02 13:06:18 +0100947char *print_icmptype(int t)
948{
949 static char *ttab[] = {
950 "Echo Reply",
951 "ICMP 1",
952 "ICMP 2",
953 "Dest Unreachable",
954 "Source Quench",
955 "Redirect",
956 "ICMP 6",
957 "ICMP 7",
958 "Echo",
959 "ICMP 9",
960 "ICMP 10",
961 "Time Exceeded",
962 "Parameter Problem",
963 "Timestamp",
964 "Timestamp Reply",
965 "Info Request",
966 "Info Reply"
967 };
968 if (t < 0 || t > 16)
969 return ("OUT-OF-RANGE");
970 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +0000971}
972
Harald Weltebed35df2011-11-02 13:06:18 +0100973int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
974{
975 unsigned int n;
976 uint64_t i64 = 0;
977 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
978 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +0000979
Harald Weltebed35df2011-11-02 13:06:18 +0100980 /* Convert to uint64_t from ul16_t format (most significant digit first) */
981 /* ul16_t format always starts with 0x91 to indicate international format */
982 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
983 for (n = 0; n < src->l; n++) {
984 if ((src->v[n] & 0x0f) != 0x0f) {
985 i64 *= 10;
986 i64 += src->v[n] & 0x0f;
987 }
988 if ((src->v[n] & 0xf0) != 0xf0) {
989 i64 *= 10;
990 i64 += (src->v[n] & 0xf0) >> 4;
991 }
992 }
jjako193e8b12003-11-10 12:31:41 +0000993
Harald Weltebed35df2011-11-02 13:06:18 +0100994 i64 += add;
jjako193e8b12003-11-10 12:31:41 +0000995
Harald Weltebed35df2011-11-02 13:06:18 +0100996 /* Generate array with least significant digit in first octet */
997 while (i64) {
998 msa[msalen++] = i64 % 10;
999 i64 = i64 / 10;
1000 }
jjako193e8b12003-11-10 12:31:41 +00001001
Harald Weltebed35df2011-11-02 13:06:18 +01001002 /* Convert back to ul16_t format */
1003 for (n = 0; n < msalen; n++) {
1004 if ((n % 2) == 0) {
1005 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
1006 dst->l += 1;
1007 } else {
1008 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
1009 msa[msalen - n - 1] * 16;
1010 }
1011 }
jjako193e8b12003-11-10 12:31:41 +00001012
Harald Weltebed35df2011-11-02 13:06:18 +01001013 return 0;
jjako193e8b12003-11-10 12:31:41 +00001014
1015}
1016
Harald Weltebed35df2011-11-02 13:06:18 +01001017int imsi_add(uint64_t src, uint64_t * dst, int add)
1018{
1019 /* TODO: big endian / small endian ??? */
1020 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001021
Harald Weltebed35df2011-11-02 13:06:18 +01001022 /* Convert from uint64_t bcd to uint64_t integer format */
1023 /* The resulting integer format is multiplied by 10 */
1024 while (src) {
1025 if ((src & 0x0f) != 0x0f) {
1026 i64 *= 10;
1027 i64 += (src & 0x0f);
1028 }
1029 if ((src & 0xf0) != 0xf0) {
1030 i64 *= 10;
1031 i64 += (src & 0xf0) >> 4;
1032 }
1033 src = src >> 8;
1034 }
jjako193e8b12003-11-10 12:31:41 +00001035
Harald Weltebed35df2011-11-02 13:06:18 +01001036 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001037
Harald Weltebed35df2011-11-02 13:06:18 +01001038 *dst = 0;
1039 while (i64) {
1040 *dst = *dst << 4;
1041 *dst += (i64 % 10);
1042 i64 = i64 / 10;
1043 }
jjako193e8b12003-11-10 12:31:41 +00001044
Harald Weltebed35df2011-11-02 13:06:18 +01001045 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001046
Harald Weltebed35df2011-11-02 13:06:18 +01001047 return 0;
jjako193e8b12003-11-10 12:31:41 +00001048
1049}
1050
jjakoafb2a972003-01-29 21:04:13 +00001051/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001052int ping_timeout(struct timeval *tp)
1053{
1054 struct timezone tz;
1055 struct timeval tv;
1056 int diff;
1057 if ((options.pinghost.s_addr) && (2 == state) &&
1058 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1059 gettimeofday(&tv, &tz);
1060 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1061 tp->tv_sec = 0;
1062 if (diff > 0)
1063 tp->tv_usec = diff;
1064 else {
1065 /* For some reason we get packet loss if set to zero */
1066 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1067 tp->tv_usec = 0;
1068 }
1069 }
1070 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001071}
1072
jjako5da68452003-01-28 16:08:47 +00001073/* Print out statistics when at the end of ping sequence */
1074int ping_finish()
1075{
Harald Weltebed35df2011-11-02 13:06:18 +01001076 struct timezone tz;
1077 struct timeval tv;
1078 int elapsed;
1079 gettimeofday(&tv, &tz);
1080 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1081 printf("\n");
1082 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1083 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1084 elapsed / 1000000.0);
1085 printf("%d packets received, ", nreceived);
1086 if (ntransmitted) {
1087 if (nreceived > ntransmitted)
1088 printf("-- somebody's printing up packets!");
1089 else
1090 printf("%d%% packet loss",
1091 (int)(((ntransmitted - nreceived) * 100) /
1092 ntransmitted));
1093 }
1094 printf("\n");
1095 if (options.debug)
1096 printf("%d packets received in total\n", ntreceived);
1097 if (nreceived && tsum)
1098 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1099 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1100 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001101
Harald Weltebed35df2011-11-02 13:06:18 +01001102 ntransmitted = 0;
1103 return 0;
jjako5da68452003-01-28 16:08:47 +00001104}
1105
1106/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001107int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1108{
1109 struct timezone tz;
1110 struct timeval tv;
1111 struct timeval *tp;
1112 struct ip_ping *pingpack = pack;
1113 struct in_addr src;
1114 int triptime;
jjako5da68452003-01-28 16:08:47 +00001115
Harald Weltebed35df2011-11-02 13:06:18 +01001116 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001117
Harald Weltebed35df2011-11-02 13:06:18 +01001118 gettimeofday(&tv, &tz);
1119 if (options.debug)
1120 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001121
Harald Weltebed35df2011-11-02 13:06:18 +01001122 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1123 printf("packet too short (%d bytes) from %s\n", len,
1124 inet_ntoa(src));
1125 return 0;
1126 }
jjako5da68452003-01-28 16:08:47 +00001127
Harald Weltebed35df2011-11-02 13:06:18 +01001128 ntreceived++;
1129 if (pingpack->protocol != 1) {
1130 if (!options.pingquiet)
1131 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1132 len, inet_ntoa(src), pingpack->protocol,
1133 print_ipprot(pingpack->protocol));
1134 return 0;
1135 }
jjako5da68452003-01-28 16:08:47 +00001136
Harald Weltebed35df2011-11-02 13:06:18 +01001137 if (pingpack->type != 0) {
1138 if (!options.pingquiet)
1139 printf
1140 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1141 len, inet_ntoa(src), pingpack->type,
1142 print_icmptype(pingpack->type), pingpack->code);
1143 return 0;
1144 }
jjako5da68452003-01-28 16:08:47 +00001145
Harald Weltebed35df2011-11-02 13:06:18 +01001146 nreceived++;
1147 if (!options.pingquiet)
1148 printf("%d bytes from %s: icmp_seq=%d", len,
1149 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001150
Harald Weltebed35df2011-11-02 13:06:18 +01001151 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1152 gettimeofday(&tv, &tz);
1153 tp = (struct timeval *)pingpack->data;
1154 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1155 tv.tv_sec--;
1156 tv.tv_usec += 1000000;
1157 }
1158 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001159
Harald Weltebed35df2011-11-02 13:06:18 +01001160 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1161 tsum += triptime;
1162 if (triptime < tmin)
1163 tmin = triptime;
1164 if (triptime > tmax)
1165 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001166
Harald Weltebed35df2011-11-02 13:06:18 +01001167 if (!options.pingquiet)
1168 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001169
Harald Weltebed35df2011-11-02 13:06:18 +01001170 } else if (!options.pingquiet)
1171 printf("\n");
1172 return 0;
jjako5da68452003-01-28 16:08:47 +00001173}
1174
1175/* Create a new ping packet and send it off to peer. */
1176int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001177 struct in_addr *dst, int seq, unsigned int datasize)
1178{
jjako5da68452003-01-28 16:08:47 +00001179
Harald Weltebed35df2011-11-02 13:06:18 +01001180 struct ip_ping pack;
1181 uint16_t *p = (uint16_t *) & pack;
1182 uint8_t *p8 = (uint8_t *) & pack;
1183 struct in_addr src;
1184 unsigned int n;
1185 long int sum = 0;
1186 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001187
Harald Weltebed35df2011-11-02 13:06:18 +01001188 struct timezone tz;
1189 struct timeval *tp =
1190 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001191
Harald Weltebed35df2011-11-02 13:06:18 +01001192 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001193 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001194 "Ping size to large: %d!", datasize);
1195 return -1;
1196 }
jjako5da68452003-01-28 16:08:47 +00001197
Harald Weltebed35df2011-11-02 13:06:18 +01001198 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001199
Harald Weltebed35df2011-11-02 13:06:18 +01001200 pack.ipver = 0x45;
1201 pack.tos = 0x00;
1202 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1203 pack.fragid = 0x0000;
1204 pack.offset = 0x0040;
1205 pack.ttl = 0x40;
1206 pack.protocol = 0x01;
1207 pack.ipcheck = 0x0000;
1208 pack.src = src.s_addr;
1209 pack.dst = dst->s_addr;
1210 pack.type = 0x08;
1211 pack.code = 0x00;
1212 pack.checksum = 0x0000;
1213 pack.ident = 0x0000;
1214 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001215
Harald Weltebed35df2011-11-02 13:06:18 +01001216 /* Generate ICMP payload */
1217 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1218 for (n = 0; n < (datasize); n++)
1219 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001220
Harald Weltebed35df2011-11-02 13:06:18 +01001221 if (datasize >= sizeof(struct timeval))
1222 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001223
Harald Weltebed35df2011-11-02 13:06:18 +01001224 /* Calculate IP header checksum */
1225 p = (uint16_t *) & pack;
1226 count = CREATEPING_IP;
1227 sum = 0;
1228 while (count > 1) {
1229 sum += *p++;
1230 count -= 2;
1231 }
1232 while (sum >> 16)
1233 sum = (sum & 0xffff) + (sum >> 16);
1234 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001235
Harald Weltebed35df2011-11-02 13:06:18 +01001236 /* Calculate ICMP checksum */
1237 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1238 sum = 0;
1239 p = (uint16_t *) & pack;
1240 p += CREATEPING_IP / 2;
1241 while (count > 1) {
1242 sum += *p++;
1243 count -= 2;
1244 }
1245 if (count > 0)
1246 sum += *(unsigned char *)p;
1247 while (sum >> 16)
1248 sum = (sum & 0xffff) + (sum >> 16);
1249 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001250
Harald Weltebed35df2011-11-02 13:06:18 +01001251 ntransmitted++;
1252 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001253}
1254
Harald Weltebed35df2011-11-02 13:06:18 +01001255int delete_context(struct pdp_t *pdp)
1256{
1257
1258 if (tun && options.ipdown)
1259 tun_runscript(tun, options.ipdown);
1260
1261 ipdel((struct iphash_t *)pdp->peer);
1262 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1263
1264 if (1 == options.contexts)
1265 state = 5; /* Disconnected */
1266
1267 return 0;
1268}
jjakoa7cd2492003-04-11 09:40:12 +00001269
1270/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001271int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1272{
1273 struct iphash_t *ipm;
1274 struct in_addr src;
1275 struct tun_packet_t *iph = (struct tun_packet_t *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001276
Harald Weltebed35df2011-11-02 13:06:18 +01001277 src.s_addr = iph->src;
jjakoa7cd2492003-04-11 09:40:12 +00001278
Harald Weltebed35df2011-11-02 13:06:18 +01001279 if (ipget(&ipm, &src)) {
Neels Hofmeyr041824d2015-10-19 13:26:39 +02001280 printf("Dropping packet from invalid source address: %s\n",
1281 inet_ntoa(src));
Harald Weltebed35df2011-11-02 13:06:18 +01001282 return 0;
1283 }
1284
1285 if (ipm->pdp) /* Check if a peer protocol is defined */
1286 gtp_data_req(gsn, ipm->pdp, pack, len);
1287 return 0;
jjako52c24142002-12-16 13:33:51 +00001288}
1289
Harald Weltebed35df2011-11-02 13:06:18 +01001290int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1291{
1292 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +00001293
Harald Weltebed35df2011-11-02 13:06:18 +01001294 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001295
Harald Weltebed35df2011-11-02 13:06:18 +01001296 if (cause < 0) {
1297 printf("Create PDP Context Request timed out\n");
1298 if (iph->pdp->version == 1) {
1299 printf("Retrying with version 0\n");
1300 iph->pdp->version = 0;
1301 gtp_create_context_req(gsn, iph->pdp, iph);
1302 return 0;
1303 } else {
1304 state = 0;
1305 pdp_freepdp(iph->pdp);
1306 iph->pdp = NULL;
1307 return EOF;
1308 }
1309 }
jjako2c381332003-10-21 19:09:53 +00001310
Harald Weltebed35df2011-11-02 13:06:18 +01001311 if (cause != 128) {
1312 printf
1313 ("Received create PDP context response. Cause value: %d\n",
1314 cause);
1315 state = 0;
1316 pdp_freepdp(iph->pdp);
1317 iph->pdp = NULL;
1318 return EOF; /* Not what we expected */
1319 }
jjako52c24142002-12-16 13:33:51 +00001320
Harald Weltebed35df2011-11-02 13:06:18 +01001321 if (pdp_euaton(&pdp->eua, &addr)) {
1322 printf
1323 ("Received create PDP context response. Cause value: %d\n",
1324 cause);
1325 pdp_freepdp(iph->pdp);
1326 iph->pdp = NULL;
1327 state = 0;
1328 return EOF; /* Not a valid IP address */
1329 }
jjakoa7cd2492003-04-11 09:40:12 +00001330
Harald Weltebed35df2011-11-02 13:06:18 +01001331 printf("Received create PDP context response. IP address: %s\n",
1332 inet_ntoa(addr));
jjakoa7cd2492003-04-11 09:40:12 +00001333
Harald Weltebed35df2011-11-02 13:06:18 +01001334 if ((options.createif) && (!options.net.s_addr)) {
1335 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +00001336#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +01001337 inet_aton("255.255.255.255", &m);
jjako1d3db972004-01-16 09:56:56 +00001338#else
Harald Weltebed35df2011-11-02 13:06:18 +01001339 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +00001340#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001341 /* printf("Setting up interface and routing\n"); */
1342 tun_addaddr(tun, &addr, &addr, &m);
1343 if (options.defaultroute) {
1344 struct in_addr rm;
1345 rm.s_addr = 0;
1346 tun_addroute(tun, &rm, &addr, &rm);
1347 }
1348 if (options.ipup)
1349 tun_runscript(tun, options.ipup);
1350 }
jjako52c24142002-12-16 13:33:51 +00001351
Harald Weltebed35df2011-11-02 13:06:18 +01001352 ipset((struct iphash_t *)pdp->peer, &addr);
1353
1354 state = 2; /* Connected */
1355
1356 return 0;
jjako52c24142002-12-16 13:33:51 +00001357}
1358
Harald Weltebed35df2011-11-02 13:06:18 +01001359int delete_pdp_conf(struct pdp_t *pdp, int cause)
1360{
1361 printf("Received delete PDP context response. Cause value: %d\n",
1362 cause);
1363 return 0;
jjako52c24142002-12-16 13:33:51 +00001364}
1365
Harald Weltebed35df2011-11-02 13:06:18 +01001366int echo_conf(int recovery)
1367{
jjako91aaf222003-10-22 10:09:32 +00001368
Harald Weltebed35df2011-11-02 13:06:18 +01001369 if (recovery < 0) {
1370 printf("Echo Request timed out\n");
1371 if (echoversion == 1) {
1372 printf("Retrying with version 0\n");
1373 echoversion = 0;
1374 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1375 return 0;
1376 } else {
1377 state = 0;
1378 return EOF;
1379 }
1380 } else {
1381 printf("Received echo response\n");
1382 if (!options.contexts)
1383 state = 5;
1384 }
1385 return 0;
jjako52c24142002-12-16 13:33:51 +00001386}
1387
Harald Weltebed35df2011-11-02 13:06:18 +01001388int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1389{
1390 /* if (cause < 0) return 0; Some error occurred. We don't care */
1391 switch (type) {
1392 case GTP_ECHO_REQ:
1393 return echo_conf(cause);
1394 case GTP_CREATE_PDP_REQ:
1395 return create_pdp_conf(pdp, cbp, cause);
1396 case GTP_DELETE_PDP_REQ:
1397 if (cause != 128)
1398 return 0; /* Request not accepted. We don't care */
1399 return delete_pdp_conf(pdp, cause);
1400 default:
1401 return 0;
1402 }
jjako52c24142002-12-16 13:33:51 +00001403}
1404
Harald Weltebed35df2011-11-02 13:06:18 +01001405int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1406{
1407 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1408 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001409}
1410
1411int main(int argc, char **argv)
1412{
Harald Weltebed35df2011-11-02 13:06:18 +01001413 fd_set fds; /* For select() */
1414 struct timeval idleTime; /* How long to select() */
1415 struct pdp_t *pdp;
1416 int n;
1417 int starttime = time(NULL); /* Time program was started */
1418 int stoptime = 0; /* Time to exit */
1419 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +00001420
Harald Weltebed35df2011-11-02 13:06:18 +01001421 struct timezone tz; /* Used for calculating ping times */
1422 struct timeval tv;
1423 int diff;
jjako52c24142002-12-16 13:33:51 +00001424
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001425 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001426
Harald Weltebed35df2011-11-02 13:06:18 +01001427 /* Process options given in configuration file and command line */
1428 if (process_options(argc, argv))
1429 exit(1);
jjako52c24142002-12-16 13:33:51 +00001430
Harald Weltebed35df2011-11-02 13:06:18 +01001431 printf("\nInitialising GTP library\n");
1432 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001433 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001434 exit(1);
1435 }
1436 if (gsn->fd0 > maxfd)
1437 maxfd = gsn->fd0;
1438 if (gsn->fd1c > maxfd)
1439 maxfd = gsn->fd1c;
1440 if (gsn->fd1u > maxfd)
1441 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001442
Harald Weltebed35df2011-11-02 13:06:18 +01001443 gtp_set_cb_delete_context(gsn, delete_context);
1444 gtp_set_cb_conf(gsn, conf);
1445 if (options.createif)
1446 gtp_set_cb_data_ind(gsn, encaps_tun);
1447 else
1448 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001449
Harald Weltebed35df2011-11-02 13:06:18 +01001450 if (options.createif) {
1451 printf("Setting up interface\n");
1452 /* Create a tunnel interface */
1453 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001454 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001455 "Failed to create tun");
1456 exit(1);
1457 }
1458 tun_set_cb_ind(tun, cb_tun_ind);
1459 if (tun->fd > maxfd)
1460 maxfd = tun->fd;
1461 }
jjakoa7cd2492003-04-11 09:40:12 +00001462
Harald Weltebed35df2011-11-02 13:06:18 +01001463 if ((options.createif) && (options.net.s_addr)) {
1464 /* printf("Setting up interface and routing\n"); */
1465 tun_addaddr(tun, &options.netaddr, &options.destaddr,
1466 &options.mask);
1467 if (options.defaultroute) {
1468 struct in_addr rm;
1469 rm.s_addr = 0;
1470 tun_addroute(tun, &rm, &options.destaddr, &rm);
1471 }
1472 if (options.ipup)
1473 tun_runscript(tun, options.ipup);
1474 }
jjakoa7cd2492003-04-11 09:40:12 +00001475
Harald Weltebed35df2011-11-02 13:06:18 +01001476 /* Initialise hash tables */
1477 memset(&iphash, 0, sizeof(iphash));
1478 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001479
Harald Weltebed35df2011-11-02 13:06:18 +01001480 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001481
Harald Weltebed35df2011-11-02 13:06:18 +01001482 /* See if anybody is there */
1483 printf("Sending off echo request\n");
1484 echoversion = options.gtpversion;
1485 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001486
Harald Weltebed35df2011-11-02 13:06:18 +01001487 for (n = 0; n < options.contexts; n++) {
1488 uint64_t myimsi;
1489 printf("Setting up PDP context #%d\n", n);
1490 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001491
Harald Weltebed35df2011-11-02 13:06:18 +01001492 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001493
Harald Weltebed35df2011-11-02 13:06:18 +01001494 /* Allocated here. */
1495 /* If create context failes we have to deallocate ourselves. */
1496 /* Otherwise it is deallocated by gtplib */
1497 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001498
Harald Weltebed35df2011-11-02 13:06:18 +01001499 pdp->peer = &iparr[n];
1500 pdp->ipif = tun; /* TODO */
1501 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001502
Harald Weltebed35df2011-11-02 13:06:18 +01001503 if (options.gtpversion == 0) {
1504 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001505 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001506 "QoS length too big");
1507 exit(1);
1508 } else {
1509 memcpy(pdp->qos_req0, options.qos.v,
1510 options.qos.l);
1511 }
1512 }
jjakoa7cd2492003-04-11 09:40:12 +00001513
Harald Weltebed35df2011-11-02 13:06:18 +01001514 pdp->qos_req.l = options.qos.l;
1515 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001516
Harald Weltebed35df2011-11-02 13:06:18 +01001517 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001518
Harald Weltebed35df2011-11-02 13:06:18 +01001519 pdp->rattype.l = options.rattype.l;
1520 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1521 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001522
Harald Weltebed35df2011-11-02 13:06:18 +01001523 pdp->userloc.l = options.userloc.l;
1524 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1525 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001526
Harald Weltebed35df2011-11-02 13:06:18 +01001527 pdp->rai.l = options.rai.l;
1528 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1529 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001530
Harald Weltebed35df2011-11-02 13:06:18 +01001531 pdp->mstz.l = options.mstz.l;
1532 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1533 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001534
Harald Weltebed35df2011-11-02 13:06:18 +01001535 pdp->imeisv.l = options.imeisv.l;
1536 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1537 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001538
Harald Weltebed35df2011-11-02 13:06:18 +01001539 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001540
Harald Weltebed35df2011-11-02 13:06:18 +01001541 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001542 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001543 "APN length too big");
1544 exit(1);
1545 } else {
1546 pdp->apn_use.l = options.apn.l;
1547 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1548 }
jjako193e8b12003-11-10 12:31:41 +00001549
Harald Weltebed35df2011-11-02 13:06:18 +01001550 pdp->gsnlc.l = sizeof(options.listen);
1551 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1552 pdp->gsnlu.l = sizeof(options.listen);
1553 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001554
Harald Weltebed35df2011-11-02 13:06:18 +01001555 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001556 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001557 "MSISDN length too big");
1558 exit(1);
1559 } else {
1560 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1561 }
jjakob62c3dd2004-05-27 18:51:55 +00001562
Harald Weltebed35df2011-11-02 13:06:18 +01001563 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
jjako52c24142002-12-16 13:33:51 +00001564
Harald Weltebed35df2011-11-02 13:06:18 +01001565 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001566 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001567 "PCO length too big");
1568 exit(1);
1569 } else {
1570 pdp->pco_req.l = options.pco.l;
1571 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1572 }
jjako52c24142002-12-16 13:33:51 +00001573
Harald Weltebed35df2011-11-02 13:06:18 +01001574 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001575
Harald Weltebed35df2011-11-02 13:06:18 +01001576 pdp->hisaddr0 = options.remote;
1577 pdp->hisaddr1 = options.remote;
1578
1579 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1580 512 = Flat rate, 256 = Hot billing */
1581
1582 /* Create context */
1583 /* We send this of once. Retransmissions are handled by gtplib */
1584 gtp_create_context_req(gsn, pdp, &iparr[n]);
1585 }
1586
1587 state = 1; /* Enter wait_connection state */
1588
1589 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001590
jjako52c24142002-12-16 13:33:51 +00001591 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001592 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001593 /******************************************************************/
1594
Harald Weltebed35df2011-11-02 13:06:18 +01001595 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001596
Harald Weltebed35df2011-11-02 13:06:18 +01001597 /* Take down client after timeout after disconnect */
1598 if ((4 == state) && ((stoptime) <= time(NULL))) {
1599 state = 5;
1600 }
jjako7b8fad42003-07-07 14:37:42 +00001601
Harald Weltebed35df2011-11-02 13:06:18 +01001602 /* Take down client after timelimit timeout */
1603 if ((2 == state) && (options.timelimit) &&
1604 ((starttime + options.timelimit) <= time(NULL))) {
1605 state = 3;
1606 }
jjako7b8fad42003-07-07 14:37:42 +00001607
Harald Weltebed35df2011-11-02 13:06:18 +01001608 /* Take down client after ping timeout */
1609 if ((2 == state) && (pingtimeout)
1610 && (pingtimeout <= time(NULL))) {
1611 state = 3;
1612 }
jjako7b8fad42003-07-07 14:37:42 +00001613
Harald Weltebed35df2011-11-02 13:06:18 +01001614 /* Set pingtimeout for later disconnection */
1615 if (options.pingcount && ntransmitted >= options.pingcount) {
1616 pingtimeout = time(NULL) + 5; /* Extra seconds */
1617 }
jjako7b8fad42003-07-07 14:37:42 +00001618
Harald Weltebed35df2011-11-02 13:06:18 +01001619 /* Print statistics if no more ping packets are missing */
1620 if (ntransmitted && options.pingcount
1621 && nreceived >= options.pingcount) {
1622 ping_finish();
1623 if (!options.createif)
1624 state = 3;
1625 }
jjako7b8fad42003-07-07 14:37:42 +00001626
Harald Weltebed35df2011-11-02 13:06:18 +01001627 /* Send off disconnect */
1628 if (3 == state) {
1629 state = 4;
1630 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1631 for (n = 0; n < options.contexts; n++) {
1632 /* Delete context */
1633 printf("Disconnecting PDP context #%d\n", n);
1634 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1635 1);
1636 if ((options.pinghost.s_addr != 0)
1637 && ntransmitted)
1638 ping_finish();
1639 }
1640 }
jjako7b8fad42003-07-07 14:37:42 +00001641
Harald Weltebed35df2011-11-02 13:06:18 +01001642 /* Send of ping packets */
1643 diff = 0;
1644 while ((diff <= 0) &&
1645 /* Send off an ICMP ping packet */
1646 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1647 ((pingseq < options.pingcount)
1648 || (options.pingcount == 0))) {
1649 if (!pingseq)
1650 gettimeofday(&firstping, &tz); /* Set time of first ping */
1651 gettimeofday(&tv, &tz);
1652 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1653 if (diff <= 0) {
1654 if (options.debug)
1655 printf("Create_ping %d\n", diff);
1656 create_ping(gsn,
1657 iparr[pingseq %
1658 options.contexts].pdp,
1659 &options.pinghost, pingseq,
1660 options.pingsize);
1661 pingseq++;
1662 }
1663 }
jjako5da68452003-01-28 16:08:47 +00001664
Harald Weltebed35df2011-11-02 13:06:18 +01001665 FD_ZERO(&fds);
1666 if (tun)
1667 FD_SET(tun->fd, &fds);
1668 FD_SET(gsn->fd0, &fds);
1669 FD_SET(gsn->fd1c, &fds);
1670 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001671
Harald Weltebed35df2011-11-02 13:06:18 +01001672 gtp_retranstimeout(gsn, &idleTime);
1673 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001674
Harald Weltebed35df2011-11-02 13:06:18 +01001675 if (options.debug)
1676 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1677 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001678
Harald Weltebed35df2011-11-02 13:06:18 +01001679 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1680 case -1:
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001681 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001682 "Select returned -1");
1683 break;
1684 case 0:
1685 gtp_retrans(gsn); /* Only retransmit if nothing else */
1686 break;
1687 default:
1688 break;
1689 }
1690
1691 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001692 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001693 "TUN decaps failed");
1694 }
1695
1696 if (FD_ISSET(gsn->fd0, &fds))
1697 gtp_decaps0(gsn);
1698
1699 if (FD_ISSET(gsn->fd1c, &fds))
1700 gtp_decaps1c(gsn);
1701
1702 if (FD_ISSET(gsn->fd1u, &fds))
1703 gtp_decaps1u(gsn);
1704 }
1705
1706 gtp_free(gsn); /* Clean up the gsn instance */
1707
1708 if (options.createif)
1709 tun_free(tun);
1710
1711 if (0 == state)
1712 exit(1); /* Indicate error */
1713
1714 return 0;
jjako52c24142002-12-16 13:33:51 +00001715}