blob: 5b56751fd4ee69697e9fb72095794610bad1dac2 [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;
234 char *lac;
235 int lac_d;
236 char *rest;
237 char *userloc_el[] = { "TYPE", "MCC", "MNC", "LAC", "REST" };
238 char *rai_el[] = { "MCC", "MNC", "LAC", "RAC" };
239 char *mstz_el[] = { "SIGN", "QUARTERS", "DST" };
240 int sign;
241 int nbquarters;
242 int DST;
jjakoa7cd2492003-04-11 09:40:12 +0000243
Harald Weltebed35df2011-11-02 13:06:18 +0100244 if (cmdline_parser(argc, argv, &args_info) != 0)
245 return -1;
246 if (args_info.debug_flag) {
247 if (args_info.remote_arg)
248 printf("remote: %s\n", args_info.remote_arg);
249 if (args_info.listen_arg)
250 printf("listen: %s\n", args_info.listen_arg);
251 if (args_info.conf_arg)
252 printf("conf: %s\n", args_info.conf_arg);
253 printf("debug: %d\n", args_info.debug_flag);
254 if (args_info.imsi_arg)
255 printf("imsi: %s\n", args_info.imsi_arg);
256 printf("qos: %#08x\n", args_info.qos_arg);
257 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
258 printf("qose2: %#04x\n", args_info.qose2_arg);
259 printf("qose3: %#06x\n", args_info.qose3_arg);
260 printf("qose4: %#06x\n", args_info.qose4_arg);
261 printf("charging: %#04x\n", args_info.charging_arg);
262 if (args_info.apn_arg)
263 printf("apn: %s\n", args_info.apn_arg);
264 if (args_info.msisdn_arg)
265 printf("msisdn: %s\n", args_info.msisdn_arg);
266 if (args_info.uid_arg)
267 printf("uid: %s\n", args_info.uid_arg);
268 if (args_info.pwd_arg)
269 printf("pwd: %s\n", args_info.pwd_arg);
270 if (args_info.pidfile_arg)
271 printf("pidfile: %s\n", args_info.pidfile_arg);
272 if (args_info.statedir_arg)
273 printf("statedir: %s\n", args_info.statedir_arg);
274 if (args_info.dns_arg)
275 printf("dns: %s\n", args_info.dns_arg);
276 printf("contexts: %d\n", args_info.contexts_arg);
277 printf("timelimit: %d\n", args_info.timelimit_arg);
278 printf("createif: %d\n", args_info.createif_flag);
279 if (args_info.ipup_arg)
280 printf("ipup: %s\n", args_info.ipup_arg);
281 if (args_info.ipdown_arg)
282 printf("ipdown: %s\n", args_info.ipdown_arg);
283 printf("defaultroute: %d\n", args_info.defaultroute_flag);
284 if (args_info.pinghost_arg)
285 printf("pinghost: %s\n", args_info.pinghost_arg);
286 printf("pingrate: %d\n", args_info.pingrate_arg);
287 printf("pingsize: %d\n", args_info.pingsize_arg);
288 printf("pingcount: %d\n", args_info.pingcount_arg);
289 printf("pingquiet: %d\n", args_info.pingquiet_flag);
290 printf("norecovery: %d\n", args_info.norecovery_flag);
Yann BONNAMY11a398f2010-11-18 10:01:21 +0100291 }
jjakoa7cd2492003-04-11 09:40:12 +0000292
Harald Weltebed35df2011-11-02 13:06:18 +0100293 /* Try out our new parser */
jjako193e8b12003-11-10 12:31:41 +0000294
Harald Weltebed35df2011-11-02 13:06:18 +0100295 if (args_info.conf_arg) {
296 if (cmdline_parser_configfile
297 (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
298 return -1;
299 if (args_info.debug_flag) {
300 printf("cmdline_parser_configfile\n");
301 if (args_info.remote_arg)
302 printf("remote: %s\n", args_info.remote_arg);
303 if (args_info.listen_arg)
304 printf("listen: %s\n", args_info.listen_arg);
305 if (args_info.conf_arg)
306 printf("conf: %s\n", args_info.conf_arg);
307 printf("debug: %d\n", args_info.debug_flag);
308 if (args_info.imsi_arg)
309 printf("imsi: %s\n", args_info.imsi_arg);
310 printf("qos: %#08x\n", args_info.qos_arg);
311 printf("qose1: %#0.16llx\n", args_info.qose1_arg);
312 printf("qose2: %#04x\n", args_info.qose2_arg);
313 printf("qose3: %#06x\n", args_info.qose3_arg);
314 printf("qose4: %#06x\n", args_info.qose4_arg);
315 printf("charging: %#04x\n", args_info.charging_arg);
316 if (args_info.apn_arg)
317 printf("apn: %s\n", args_info.apn_arg);
318 if (args_info.msisdn_arg)
319 printf("msisdn: %s\n", args_info.msisdn_arg);
320 if (args_info.uid_arg)
321 printf("uid: %s\n", args_info.uid_arg);
322 if (args_info.pwd_arg)
323 printf("pwd: %s\n", args_info.pwd_arg);
324 if (args_info.pidfile_arg)
325 printf("pidfile: %s\n", args_info.pidfile_arg);
326 if (args_info.statedir_arg)
327 printf("statedir: %s\n",
328 args_info.statedir_arg);
329 if (args_info.dns_arg)
330 printf("dns: %s\n", args_info.dns_arg);
331 printf("contexts: %d\n", args_info.contexts_arg);
332 printf("timelimit: %d\n", args_info.timelimit_arg);
333 printf("createif: %d\n", args_info.createif_flag);
334 if (args_info.ipup_arg)
335 printf("ipup: %s\n", args_info.ipup_arg);
336 if (args_info.ipdown_arg)
337 printf("ipdown: %s\n", args_info.ipdown_arg);
338 printf("defaultroute: %d\n",
339 args_info.defaultroute_flag);
340 if (args_info.pinghost_arg)
341 printf("pinghost: %s\n",
342 args_info.pinghost_arg);
343 printf("pingrate: %d\n", args_info.pingrate_arg);
344 printf("pingsize: %d\n", args_info.pingsize_arg);
345 printf("pingcount: %d\n", args_info.pingcount_arg);
346 printf("pingquiet: %d\n", args_info.pingquiet_flag);
347 printf("norecovery: %d\n", args_info.norecovery_flag);
348 }
349 }
jjako193e8b12003-11-10 12:31:41 +0000350
Harald Weltebed35df2011-11-02 13:06:18 +0100351 /* Handle each option */
jjako1a51df72004-07-20 08:30:21 +0000352
Harald Weltebed35df2011-11-02 13:06:18 +0100353 /* foreground */
354 /* If fg flag not given run as a daemon */
355 /* Do not allow sgsnemu to run as deamon
356 if (!args_info.fg_flag)
357 {
358 closelog();
359 freopen("/dev/null", "w", stdout);
360 freopen("/dev/null", "w", stderr);
361 freopen("/dev/null", "r", stdin);
362 daemon(0, 0);
363 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
364 } */
jjako1a51df72004-07-20 08:30:21 +0000365
Harald Weltebed35df2011-11-02 13:06:18 +0100366 /* debug */
367 options.debug = args_info.debug_flag;
jjako1a51df72004-07-20 08:30:21 +0000368
Harald Weltebed35df2011-11-02 13:06:18 +0100369 /* pidfile */
370 /* This has to be done after we have our final pid */
371 if (args_info.pidfile_arg) {
372 log_pid(args_info.pidfile_arg);
373 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200374
Harald Weltebed35df2011-11-02 13:06:18 +0100375 /* dns */
376 /* If no dns option is given use system default */
377 /* Do hostname lookup to translate hostname to IP address */
378 printf("\n");
379 if (args_info.dns_arg) {
380 if (!(host = gethostbyname(args_info.dns_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100381 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100382 "Invalid DNS address: %s!", args_info.dns_arg);
383 return -1;
384 } else {
385 memcpy(&options.dns.s_addr, host->h_addr,
386 host->h_length);
387 _res.nscount = 1;
388 _res.nsaddr_list[0].sin_addr = options.dns;
389 printf("Using DNS server: %s (%s)\n",
390 args_info.dns_arg, inet_ntoa(options.dns));
391 }
392 } else {
393 options.dns.s_addr = 0;
394 printf("Using default DNS server\n");
395 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200396
Harald Weltebed35df2011-11-02 13:06:18 +0100397 /* listen */
398 /* If no listen option is specified listen to any local port */
399 /* Do hostname lookup to translate hostname to IP address */
400 if (args_info.listen_arg) {
401 if (!(host = gethostbyname(args_info.listen_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100402 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100403 "Invalid listening address: %s!",
404 args_info.listen_arg);
405 return -1;
406 } else {
407 memcpy(&options.listen.s_addr, host->h_addr,
408 host->h_length);
409 printf("Local IP address is: %s (%s)\n",
410 args_info.listen_arg, inet_ntoa(options.listen));
411 }
412 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100413 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100414 "Listening address must be specified: %s!",
415 args_info.listen_arg);
416 return -1;
417 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200418
Harald Weltebed35df2011-11-02 13:06:18 +0100419 /* remote */
420 /* If no remote option is specified terminate */
421 /* Do hostname lookup to translate hostname to IP address */
422 if (args_info.remote_arg) {
423 if (!(host = gethostbyname(args_info.remote_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100424 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100425 "Invalid remote address: %s!",
426 args_info.remote_arg);
427 return -1;
428 } else {
429 memcpy(&options.remote.s_addr, host->h_addr,
430 host->h_length);
431 printf("Remote IP address is: %s (%s)\n",
432 args_info.remote_arg, inet_ntoa(options.remote));
433 }
434 } else {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100435 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100436 "No remote address given!");
437 return -1;
438 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200439
Harald Weltebed35df2011-11-02 13:06:18 +0100440 /* imsi */
441 if (strlen(args_info.imsi_arg) != 15) {
442 printf("Invalid IMSI\n");
443 return -1;
444 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200445
Harald Weltebed35df2011-11-02 13:06:18 +0100446 options.imsi = 0xf000000000000000ull;
447 options.imsi |= ((uint64_t) (args_info.imsi_arg[0] - 48));
448 options.imsi |= ((uint64_t) (args_info.imsi_arg[1] - 48)) << 4;
449 options.imsi |= ((uint64_t) (args_info.imsi_arg[2] - 48)) << 8;
450 options.imsi |= ((uint64_t) (args_info.imsi_arg[3] - 48)) << 12;
451 options.imsi |= ((uint64_t) (args_info.imsi_arg[4] - 48)) << 16;
452 options.imsi |= ((uint64_t) (args_info.imsi_arg[5] - 48)) << 20;
453 options.imsi |= ((uint64_t) (args_info.imsi_arg[6] - 48)) << 24;
454 options.imsi |= ((uint64_t) (args_info.imsi_arg[7] - 48)) << 28;
455 options.imsi |= ((uint64_t) (args_info.imsi_arg[8] - 48)) << 32;
456 options.imsi |= ((uint64_t) (args_info.imsi_arg[9] - 48)) << 36;
457 options.imsi |= ((uint64_t) (args_info.imsi_arg[10] - 48)) << 40;
458 options.imsi |= ((uint64_t) (args_info.imsi_arg[11] - 48)) << 44;
459 options.imsi |= ((uint64_t) (args_info.imsi_arg[12] - 48)) << 48;
460 options.imsi |= ((uint64_t) (args_info.imsi_arg[13] - 48)) << 52;
461 options.imsi |= ((uint64_t) (args_info.imsi_arg[14] - 48)) << 56;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200462
Harald Weltebed35df2011-11-02 13:06:18 +0100463 printf("IMSI is: %s (%#08llx)\n",
464 args_info.imsi_arg, options.imsi);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200465
Harald Weltebed35df2011-11-02 13:06:18 +0100466 /* nsapi */
467 if ((args_info.nsapi_arg > 15) || (args_info.nsapi_arg < 0)) {
468 printf("Invalid NSAPI\n");
469 return -1;
470 }
471 options.nsapi = args_info.nsapi_arg;
472 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
Yann BONNAMY944dce32010-10-29 17:07:44 +0200473
Harald Weltebed35df2011-11-02 13:06:18 +0100474 /* qos */
475 options.qos.l = 4;
476 options.qos.v[3] = (args_info.qos_arg) & 0xff;
477 options.qos.v[2] = ((args_info.qos_arg) >> 8) & 0xff;
478 options.qos.v[1] = ((args_info.qos_arg) >> 16) & 0xff;
479 options.qos.v[0] = ((args_info.qos_arg) >> 24) & 0xff;
480 /* Extensions according to 3GPP TS 24.008 */
481 if (args_info.qose1_given == 1) {
482 options.qos.l = 12;
483 options.qos.v[11] = (args_info.qose1_arg) & 0xff;
484 options.qos.v[10] = ((args_info.qose1_arg) >> 8) & 0xff;
485 options.qos.v[9] = ((args_info.qose1_arg) >> 16) & 0xff;
486 options.qos.v[8] = ((args_info.qose1_arg) >> 24) & 0xff;
487 options.qos.v[7] = ((args_info.qose1_arg) >> 32) & 0xff;
488 options.qos.v[6] = ((args_info.qose1_arg) >> 40) & 0xff;
489 options.qos.v[5] = ((args_info.qose1_arg) >> 48) & 0xff;
490 options.qos.v[4] = ((args_info.qose1_arg) >> 56) & 0xff;
491 if (args_info.qose2_given == 1) {
492 options.qos.l = 13;
493 options.qos.v[12] = (args_info.qose2_arg) & 0xff;
494 if (args_info.qose3_given == 1) {
495 options.qos.l = 15;
496 options.qos.v[14] =
497 (args_info.qose3_arg) & 0xff;
498 options.qos.v[13] =
499 ((args_info.qose3_arg) >> 8) & 0xff;
500 if (args_info.qose4_given == 1) {
501 options.qos.l = 17;
502 options.qos.v[16] =
503 (args_info.qose4_arg) & 0xff;
504 options.qos.v[15] =
505 ((args_info.qose4_arg) >> 8) & 0xff;
506 }
507 }
508 }
509 }
Yann BONNAMY944dce32010-10-29 17:07:44 +0200510
Harald Weltebed35df2011-11-02 13:06:18 +0100511 /* charging */
512 options.cch = args_info.charging_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200513
Harald Weltebed35df2011-11-02 13:06:18 +0100514 /* contexts */
515 if (args_info.contexts_arg > MAXCONTEXTS) {
516 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
517 return -1;
518 }
519 options.contexts = args_info.contexts_arg;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200520
Harald Weltebed35df2011-11-02 13:06:18 +0100521 /* Timelimit */
522 options.timelimit = args_info.timelimit_arg;
Harald Welte41af5692011-10-07 18:42:34 +0200523
Harald Weltebed35df2011-11-02 13:06:18 +0100524 /* gtpversion */
525 if ((args_info.gtpversion_arg > 1) || (args_info.gtpversion_arg < 0)) {
526 printf("Invalid GTP version\n");
527 return -1;
528 }
529 options.gtpversion = args_info.gtpversion_arg;
530 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200531
Harald Weltebed35df2011-11-02 13:06:18 +0100532 /* apn */
533 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v) - 1)) {
534 printf("Invalid APN\n");
535 return -1;
536 }
537 options.apn.l = strlen(args_info.apn_arg);
538 strncpy((char *)options.apn.v, args_info.apn_arg,
539 sizeof(options.apn.v));
540 options.apn.v[sizeof(options.apn.v) - 1] = 0;
541 printf("Using APN: %s\n", args_info.apn_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200542
Harald Weltebed35df2011-11-02 13:06:18 +0100543 /* selmode */
544 options.selmode = args_info.selmode_arg;
545 printf("Using selection mode: %d\n", args_info.selmode_arg);
Harald Welte41af5692011-10-07 18:42:34 +0200546
Harald Weltebed35df2011-11-02 13:06:18 +0100547 /* rattype */
548 if (args_info.rattype_given == 1) {
549 options.rattype_given = 1;
550 options.rattype.l = strlen(args_info.rattype_arg);
551 options.rattype.v[0] = atoi(args_info.rattype_arg);
552 printf("Using RAT Type: %s\n", args_info.rattype_arg);
553 }
Harald Welte41af5692011-10-07 18:42:34 +0200554
Harald Weltebed35df2011-11-02 13:06:18 +0100555 /* userloc */
556 if (args_info.userloc_given == 1) {
557 printf("Using User Location Information: %s\n",
558 args_info.userloc_arg);
559 tmp = args_info.userloc_arg;
560 n = 0;
561 pch = strtok(tmp, ".");
562 while (pch != NULL) {
563 userloc_el[n] = pch;
564 pch = strtok(NULL, ".");
565 n++;
566 }
Harald Welte41af5692011-10-07 18:42:34 +0200567
Harald Weltebed35df2011-11-02 13:06:18 +0100568 options.userloc_given = 1;
569 options.userloc.l = 8;
Harald Welte41af5692011-10-07 18:42:34 +0200570
Harald Weltebed35df2011-11-02 13:06:18 +0100571 /* 3GPP Geographic Location Type t0 / t1 / t2 */
572 type = userloc_el[0];
573 printf("->type : %c\n", type[0]);
574 if ((strlen(type) != 1) || (!isdigit(type[0]))) {
575 printf("Invalid type \n");
576 return -1;
577 }
578 /* options.userloc.v[0] = 0x00 */
579 options.userloc.v[0] = type[0] - 48;
Harald Welte41af5692011-10-07 18:42:34 +0200580
Harald Weltebed35df2011-11-02 13:06:18 +0100581 /* MCC */
582 mcc = userloc_el[1];
583 printf("->mcc : %s\n", mcc);
584 if (strlen(mcc) != 3) {
585 printf("Invalid MCC lenght\n");
586 return -1;
587 }
Harald Welte41af5692011-10-07 18:42:34 +0200588
Harald Weltebed35df2011-11-02 13:06:18 +0100589 /* MNC */
590 mnc = userloc_el[2];
591 printf("->mnc : %s\n", mnc);
Harald Welte41af5692011-10-07 18:42:34 +0200592
Harald Weltebed35df2011-11-02 13:06:18 +0100593 /* octet 5 - MCC Digit 2 - MCC Digit 1 */
594 /* options.userloc.v[1] = 0x52 */
595 a = (uint8_t) (mcc[0] - 48);
596 b = (uint8_t) (mcc[1] - 48);
597 options.userloc.v[1] = 16 * b + a;
Harald Welte41af5692011-10-07 18:42:34 +0200598
Harald Weltebed35df2011-11-02 13:06:18 +0100599 /* octet 6 - MNC Digit 3 - MCC Digit 3 */
600 /* options.userloc.v[2] = 0xf0 */
601 a = (uint8_t) (mcc[2] - 48);
Harald Welte41af5692011-10-07 18:42:34 +0200602
Harald Weltebed35df2011-11-02 13:06:18 +0100603 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
604 printf("Invalid MNC lenght\n");
605 return -1;
606 }
607 if (strlen(mnc) == 2) {
608 b = 15;
609 }
610 if (strlen(mnc) == 3) {
611 b = (uint8_t) (mnc[2] - 48);
612 }
613 options.userloc.v[2] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200614
Harald Weltebed35df2011-11-02 13:06:18 +0100615 /* octet 7 - MNC Digit 2 - MNC Digit 1 */
616 /* options.userloc.v[3] = 0x99 */
617 a = (uint8_t) (mnc[0] - 48);
618 b = (uint8_t) (mnc[1] - 48);
619 options.userloc.v[3] = 16 * b + a;
Yann BONNAMY944dce32010-10-29 17:07:44 +0200620
Harald Weltebed35df2011-11-02 13:06:18 +0100621 /* LAC */
622 lac = userloc_el[3];
623 /*options.userloc.v[4] = 0x12 ; */
624 /*options.userloc.v[5] = 0x10 ; */
625 printf("->LAC: %s\n", lac);
626 lac_d = atoi(lac);
627 if (lac_d > 65535 || lac_d < 1) {
628 printf("Invalid LAC\n");
629 return -1;
630 }
631 i = lac_d >> 8;
632 options.userloc.v[4] = i; /* octet 8 - LAC */
633 options.userloc.v[5] = lac_d; /* octet 9 - LAC */
Yann BONNAMY944dce32010-10-29 17:07:44 +0200634
Harald Weltebed35df2011-11-02 13:06:18 +0100635 /* CI/SAC/RAC */
636 rest = userloc_el[4];
637 printf("->CI/SAC/RAC : %s\n", rest);
638 lac_d = atoi(rest);
639 if (lac_d > 65535 || lac_d < 1) {
640 printf("Invalid CI/SAC/RAC\n");
641 return -1;
642 }
643 /*options.userloc.v[6] = 0x04 ; */
644 /*options.userloc.v[7] = 0xb7 ; */
645 i = lac_d >> 8;
646 options.userloc.v[6] = i; /* octet 10 - t0,CI / t1,SAC / t2,RAC */
647 options.userloc.v[7] = lac_d; /* octet 11 - t0,CI / t1,SAC / t2,RAC */
648 }
jjakoa7cd2492003-04-11 09:40:12 +0000649
Harald Weltebed35df2011-11-02 13:06:18 +0100650 /* RAI */
651 if (args_info.rai_given == 1) {
652 printf("Using RAI: %s\n", args_info.rai_arg);
653 tmp = args_info.rai_arg;
654 n = 0;
655 pch = strtok(tmp, ".");
656 while (pch != NULL) {
657 rai_el[n] = pch;
658 pch = strtok(NULL, ".");
659 n++;
660 }
jjakoa7cd2492003-04-11 09:40:12 +0000661
Harald Weltebed35df2011-11-02 13:06:18 +0100662 options.rai_given = 1;
663 options.rai.l = 6;
jjakoc6762cf2004-04-28 14:52:58 +0000664
Harald Weltebed35df2011-11-02 13:06:18 +0100665 /* MCC */
666 mcc = rai_el[0];
667 printf("->mcc : %s\n", mcc);
668 if (strlen(mcc) != 3) {
669 printf("Invalid MCC lenght\n");
670 return -1;
671 }
672
673 /* MNC */
674 mnc = rai_el[1];
675 printf("->mnc : %s\n", mnc);
676
677 a = (uint8_t) (mcc[0] - 48);
678 b = (uint8_t) (mcc[1] - 48);
679 options.rai.v[0] = 16 * b + a;
680
681 /* octet 3 - MNC Digit 3 - MCC Digit 3 */
682 a = (uint8_t) (mcc[2] - 48);
683
684 if ((strlen(mnc) > 3) || (strlen(mnc) < 2)) {
685 printf("Invalid MNC lenght\n");
686 return -1;
687 }
688 if (strlen(mnc) == 2) {
689 b = 15;
690 }
691 if (strlen(mnc) == 3) {
692 b = (uint8_t) (mnc[2] - 48);
693 }
694 options.rai.v[1] = 16 * b + a;
695
696 /* octet 4 - MNC Digit 2 - MNC Digit 1 */
697 a = (uint8_t) (mnc[0] - 48);
698 b = (uint8_t) (mnc[1] - 48);
699 options.rai.v[2] = 16 * b + a;
700
701 /* LAC */
702 lac = rai_el[2];
703 printf("->LAC: %s\n", lac);
704 lac_d = atoi(lac);
705 if (lac_d > 65535 || lac_d < 1) {
706 printf("Invalid LAC\n");
707 return -1;
708 }
709 i = lac_d >> 8;
710 options.rai.v[3] = i; /* octet 5 - LAC */
711 options.rai.v[4] = lac_d; /* octet 6 - LAC */
712
713 /* RAC */
714 rest = rai_el[3];
715 printf("->RAC : %s\n", rest);
716 lac_d = atoi(rest);
717 if (lac_d > 255 || lac_d < 1) {
718 printf("Invalid RAC\n");
719 return -1;
720 }
721 options.rai.v[5] = lac_d; /* octet 7 - RAC */
722 }
723
724 /* mstz */
725 if (args_info.mstz_given == 1) {
726 options.mstz_given = 1;
727 options.mstz.l = 2;
728
729 printf("Using MS Time Zone: %s\n", args_info.mstz_arg);
730 tmp = args_info.mstz_arg;
731 n = 0;
732 pch = strtok(tmp, ".");
733 while (pch != NULL) {
734 mstz_el[n] = pch;
735 pch = strtok(NULL, ".");
736 n++;
737 }
738
739 /* sign */
740 sign = atoi(mstz_el[0]);
741 printf("->Sign (0=+ / 1=-): %d\n", sign);
742 if (sign != 0 && sign != 1) {
743 printf("Invalid Sign \n");
744 return -1;
745 }
746 /* nbquarters */
747 nbquarters = atoi(mstz_el[1]);
748 printf("->Number of Quarters of an Hour : %d\n", nbquarters);
749 if (nbquarters < 0 || nbquarters > 79) {
750 printf("Invalid Number of Quarters \n");
751 return -1;
752 }
753 /* DST */
754 DST = atoi(mstz_el[2]);
755 printf("->Daylight Saving Time Adjustment : %d\n", DST);
756 if (DST < 0 || DST > 3) {
757 printf("Invalid DST Adjustment \n");
758 return -1;
759 }
760 /* 12345678
761 bits 123 = unit of # of quarters of an hour
762 bits 678 = # of quarters of an hour / 10
763 bit 5 = sign
764 */
765 i = nbquarters % 10;
766 i = i << 4;
767 i = i + nbquarters / 10 + 8 * sign;
768 /* options.mstz.v[0] = 0x69 ; */
769 /* options.mstz.v[1] = 0x01 ; */
770 options.mstz.v[0] = i;
771 options.mstz.v[1] = DST;
772 n = (i & 0x08) ? '-' : '+';
773 printf
774 ("->Human Readable MS Time Zone : GMT %c %d hours %d minutes\n",
775 n, nbquarters / 4, nbquarters % 4 * 15);
776 }
777
778 /* imeisv */
779 if (args_info.imeisv_given == 1) {
780 options.imeisv_given = 1;
781 if (strlen(args_info.imeisv_arg) != 16) {
782 printf("Invalid IMEI(SV)\n");
783 return -1;
784 }
785 options.imeisv.l = 8;
786 for (n = 0; n < 8; n++) {
787 a = (uint8_t) (args_info.imeisv_arg[2 * n] - 48);
788 b = (uint8_t) (args_info.imeisv_arg[2 * n + 1] - 48);
789 options.imeisv.v[n] = 16 * b + a;
790 }
791 printf("Using IMEI(SV): %s\n", args_info.imeisv_arg);
792 }
793
794 /* msisdn */
795 if (strlen(args_info.msisdn_arg) > (sizeof(options.msisdn.v) - 1)) {
796 printf("Invalid MSISDN\n");
797 return -1;
798 }
799 options.msisdn.l = 1;
800 options.msisdn.v[0] = 0x91; /* International format */
801 for (n = 0; n < strlen(args_info.msisdn_arg); n++) {
802 if ((n % 2) == 0) {
803 options.msisdn.v[((int)n / 2) + 1] =
804 args_info.msisdn_arg[n] - 48 + 0xf0;
805 options.msisdn.l += 1;
806 } else {
807 options.msisdn.v[((int)n / 2) + 1] =
808 (options.msisdn.v[((int)n / 2) + 1] & 0x0f) +
809 (args_info.msisdn_arg[n] - 48) * 16;
810 }
811 }
812 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
813
814 /* UID and PWD */
815 /* Might need to also insert stuff like DNS etc. */
816 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10) >
817 (sizeof(options.pco.v) - 1)) {
818 printf("invalid UID and PWD\n");
819 return -1;
820 }
821 options.pco.l =
822 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
823 options.pco.v[0] = 0x80; /* PPP */
824 options.pco.v[1] = 0xc0; /* PAP */
825 options.pco.v[2] = 0x23;
826 options.pco.v[3] =
827 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
828 options.pco.v[4] = 0x01; /* Authenticate request */
829 options.pco.v[5] = 0x01;
830 options.pco.v[6] = 0x00; /* MSB of length */
831 options.pco.v[7] =
832 strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
833 options.pco.v[8] = strlen(args_info.uid_arg);
834 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
835 options.pco.v[9 + strlen(args_info.uid_arg)] =
836 strlen(args_info.pwd_arg);
837 memcpy(&options.pco.v[10 + strlen(args_info.uid_arg)],
838 args_info.pwd_arg, strlen(args_info.pwd_arg));
839
840 /* createif */
841 options.createif = args_info.createif_flag;
842
843 /* net */
844 /* Store net as in_addr net and mask */
845 if (args_info.net_arg) {
846 if (ippool_aton
847 (&options.net, &options.mask, args_info.net_arg, 0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100848 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100849 "Invalid network address: %s!",
850 args_info.net_arg);
851 exit(1);
852 }
jjakoc6762cf2004-04-28 14:52:58 +0000853#if defined (__sun__)
Harald Weltebed35df2011-11-02 13:06:18 +0100854 options.netaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
855 options.destaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
jjakoc6762cf2004-04-28 14:52:58 +0000856#else
Harald Weltebed35df2011-11-02 13:06:18 +0100857 options.netaddr.s_addr = options.net.s_addr;
858 options.destaddr.s_addr = options.net.s_addr;
jjakoc6762cf2004-04-28 14:52:58 +0000859#endif
860
Harald Weltebed35df2011-11-02 13:06:18 +0100861 } else {
862 options.net.s_addr = 0;
863 options.mask.s_addr = 0;
864 options.netaddr.s_addr = 0;
865 options.destaddr.s_addr = 0;
866 }
jjako193e8b12003-11-10 12:31:41 +0000867
Harald Weltebed35df2011-11-02 13:06:18 +0100868 /* ipup */
869 options.ipup = args_info.ipup_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000870
Harald Weltebed35df2011-11-02 13:06:18 +0100871 /* ipdown */
872 options.ipdown = args_info.ipdown_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000873
Harald Weltebed35df2011-11-02 13:06:18 +0100874 /* statedir */
875 options.statedir = args_info.statedir_arg;
jjakoa7cd2492003-04-11 09:40:12 +0000876
Harald Weltebed35df2011-11-02 13:06:18 +0100877 /* defaultroute */
878 options.defaultroute = args_info.defaultroute_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000879
Harald Weltebed35df2011-11-02 13:06:18 +0100880 /* pinghost */
881 /* Store ping host as in_addr */
882 if (args_info.pinghost_arg) {
883 if (!(host = gethostbyname(args_info.pinghost_arg))) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +0100884 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +0100885 "Invalid ping host: %s!",
886 args_info.pinghost_arg);
887 return -1;
888 } else {
889 memcpy(&options.pinghost.s_addr, host->h_addr,
890 host->h_length);
891 printf("Using ping host: %s (%s)\n",
892 args_info.pinghost_arg,
893 inet_ntoa(options.pinghost));
894 }
895 }
jjakoa7cd2492003-04-11 09:40:12 +0000896
Harald Weltebed35df2011-11-02 13:06:18 +0100897 /* Other ping parameters */
898 options.pingrate = args_info.pingrate_arg;
899 options.pingsize = args_info.pingsize_arg;
900 options.pingcount = args_info.pingcount_arg;
901 options.pingquiet = args_info.pingquiet_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000902
Harald Weltebed35df2011-11-02 13:06:18 +0100903 /* norecovery */
904 options.norecovery_given = args_info.norecovery_flag;
jjakoa7cd2492003-04-11 09:40:12 +0000905
Harald Weltebed35df2011-11-02 13:06:18 +0100906 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000907
908}
909
Harald Weltebed35df2011-11-02 13:06:18 +0100910int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len)
911{
912 unsigned int i;
913 printf("The packet looks like this:\n");
914 for (i = 0; i < len; i++) {
915 printf("%02x ", (unsigned char)*(char *)(pack + i));
916 if (!((i + 1) % 16))
917 printf("\n");
918 };
919 printf("\n");
920 return 0;
jjako52c24142002-12-16 13:33:51 +0000921}
922
Harald Weltebed35df2011-11-02 13:06:18 +0100923char *print_ipprot(int t)
924{
925 switch (t) {
926 case 1:
927 return "ICMP";
928 case 6:
929 return "TCP";
930 case 17:
931 return "UDP";
932 default:
933 return "Unknown";
934 };
jjako5da68452003-01-28 16:08:47 +0000935}
936
Harald Weltebed35df2011-11-02 13:06:18 +0100937char *print_icmptype(int t)
938{
939 static char *ttab[] = {
940 "Echo Reply",
941 "ICMP 1",
942 "ICMP 2",
943 "Dest Unreachable",
944 "Source Quench",
945 "Redirect",
946 "ICMP 6",
947 "ICMP 7",
948 "Echo",
949 "ICMP 9",
950 "ICMP 10",
951 "Time Exceeded",
952 "Parameter Problem",
953 "Timestamp",
954 "Timestamp Reply",
955 "Info Request",
956 "Info Reply"
957 };
958 if (t < 0 || t > 16)
959 return ("OUT-OF-RANGE");
960 return (ttab[t]);
jjako5da68452003-01-28 16:08:47 +0000961}
962
Harald Weltebed35df2011-11-02 13:06:18 +0100963int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add)
964{
965 unsigned int n;
966 uint64_t i64 = 0;
967 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
968 unsigned int msalen = 0;
jjako193e8b12003-11-10 12:31:41 +0000969
Harald Weltebed35df2011-11-02 13:06:18 +0100970 /* Convert to uint64_t from ul16_t format (most significant digit first) */
971 /* ul16_t format always starts with 0x91 to indicate international format */
972 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
973 for (n = 0; n < src->l; n++) {
974 if ((src->v[n] & 0x0f) != 0x0f) {
975 i64 *= 10;
976 i64 += src->v[n] & 0x0f;
977 }
978 if ((src->v[n] & 0xf0) != 0xf0) {
979 i64 *= 10;
980 i64 += (src->v[n] & 0xf0) >> 4;
981 }
982 }
jjako193e8b12003-11-10 12:31:41 +0000983
Harald Weltebed35df2011-11-02 13:06:18 +0100984 i64 += add;
jjako193e8b12003-11-10 12:31:41 +0000985
Harald Weltebed35df2011-11-02 13:06:18 +0100986 /* Generate array with least significant digit in first octet */
987 while (i64) {
988 msa[msalen++] = i64 % 10;
989 i64 = i64 / 10;
990 }
jjako193e8b12003-11-10 12:31:41 +0000991
Harald Weltebed35df2011-11-02 13:06:18 +0100992 /* Convert back to ul16_t format */
993 for (n = 0; n < msalen; n++) {
994 if ((n % 2) == 0) {
995 dst->v[((int)n / 2)] = msa[msalen - n - 1] + 0xf0;
996 dst->l += 1;
997 } else {
998 dst->v[((int)n / 2)] = (dst->v[((int)n / 2)] & 0x0f) +
999 msa[msalen - n - 1] * 16;
1000 }
1001 }
jjako193e8b12003-11-10 12:31:41 +00001002
Harald Weltebed35df2011-11-02 13:06:18 +01001003 return 0;
jjako193e8b12003-11-10 12:31:41 +00001004
1005}
1006
Harald Weltebed35df2011-11-02 13:06:18 +01001007int imsi_add(uint64_t src, uint64_t * dst, int add)
1008{
1009 /* TODO: big endian / small endian ??? */
1010 uint64_t i64 = 0;
jjako193e8b12003-11-10 12:31:41 +00001011
Harald Weltebed35df2011-11-02 13:06:18 +01001012 /* Convert from uint64_t bcd to uint64_t integer format */
1013 /* The resulting integer format is multiplied by 10 */
1014 while (src) {
1015 if ((src & 0x0f) != 0x0f) {
1016 i64 *= 10;
1017 i64 += (src & 0x0f);
1018 }
1019 if ((src & 0xf0) != 0xf0) {
1020 i64 *= 10;
1021 i64 += (src & 0xf0) >> 4;
1022 }
1023 src = src >> 8;
1024 }
jjako193e8b12003-11-10 12:31:41 +00001025
Harald Weltebed35df2011-11-02 13:06:18 +01001026 i64 += add * 10;
jjako193e8b12003-11-10 12:31:41 +00001027
Harald Weltebed35df2011-11-02 13:06:18 +01001028 *dst = 0;
1029 while (i64) {
1030 *dst = *dst << 4;
1031 *dst += (i64 % 10);
1032 i64 = i64 / 10;
1033 }
jjako193e8b12003-11-10 12:31:41 +00001034
Harald Weltebed35df2011-11-02 13:06:18 +01001035 *dst |= 0xf000000000000000ull;
jjako06e9f122004-01-19 18:37:58 +00001036
Harald Weltebed35df2011-11-02 13:06:18 +01001037 return 0;
jjako193e8b12003-11-10 12:31:41 +00001038
1039}
1040
jjakoafb2a972003-01-29 21:04:13 +00001041/* Calculate time left until we have to send off next ping packet */
Harald Weltebed35df2011-11-02 13:06:18 +01001042int ping_timeout(struct timeval *tp)
1043{
1044 struct timezone tz;
1045 struct timeval tv;
1046 int diff;
1047 if ((options.pinghost.s_addr) && (2 == state) &&
1048 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1049 gettimeofday(&tv, &tz);
1050 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1051 tp->tv_sec = 0;
1052 if (diff > 0)
1053 tp->tv_usec = diff;
1054 else {
1055 /* For some reason we get packet loss if set to zero */
1056 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
1057 tp->tv_usec = 0;
1058 }
1059 }
1060 return 0;
jjakoafb2a972003-01-29 21:04:13 +00001061}
1062
jjako5da68452003-01-28 16:08:47 +00001063/* Print out statistics when at the end of ping sequence */
1064int ping_finish()
1065{
Harald Weltebed35df2011-11-02 13:06:18 +01001066 struct timezone tz;
1067 struct timeval tv;
1068 int elapsed;
1069 gettimeofday(&tv, &tz);
1070 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */
1071 printf("\n");
1072 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
1073 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
1074 elapsed / 1000000.0);
1075 printf("%d packets received, ", nreceived);
1076 if (ntransmitted) {
1077 if (nreceived > ntransmitted)
1078 printf("-- somebody's printing up packets!");
1079 else
1080 printf("%d%% packet loss",
1081 (int)(((ntransmitted - nreceived) * 100) /
1082 ntransmitted));
1083 }
1084 printf("\n");
1085 if (options.debug)
1086 printf("%d packets received in total\n", ntreceived);
1087 if (nreceived && tsum)
1088 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
1089 tmin / 1000.0, tsum / 1000.0 / nreceived, tmax / 1000.0);
1090 printf("%d packets transmitted \n", ntreceived);
jjakoafb2a972003-01-29 21:04:13 +00001091
Harald Weltebed35df2011-11-02 13:06:18 +01001092 ntransmitted = 0;
1093 return 0;
jjako5da68452003-01-28 16:08:47 +00001094}
1095
1096/* Handle a received ping packet. Print out line and update statistics. */
Harald Weltebed35df2011-11-02 13:06:18 +01001097int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len)
1098{
1099 struct timezone tz;
1100 struct timeval tv;
1101 struct timeval *tp;
1102 struct ip_ping *pingpack = pack;
1103 struct in_addr src;
1104 int triptime;
jjako5da68452003-01-28 16:08:47 +00001105
Harald Weltebed35df2011-11-02 13:06:18 +01001106 src.s_addr = pingpack->src;
jjako5da68452003-01-28 16:08:47 +00001107
Harald Weltebed35df2011-11-02 13:06:18 +01001108 gettimeofday(&tv, &tz);
1109 if (options.debug)
1110 printf("%d.%6d ", (int)tv.tv_sec, (int)tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +00001111
Harald Weltebed35df2011-11-02 13:06:18 +01001112 if (len < CREATEPING_IP + CREATEPING_ICMP) {
1113 printf("packet too short (%d bytes) from %s\n", len,
1114 inet_ntoa(src));
1115 return 0;
1116 }
jjako5da68452003-01-28 16:08:47 +00001117
Harald Weltebed35df2011-11-02 13:06:18 +01001118 ntreceived++;
1119 if (pingpack->protocol != 1) {
1120 if (!options.pingquiet)
1121 printf("%d bytes from %s: ip_protocol=%d (%s)\n",
1122 len, inet_ntoa(src), pingpack->protocol,
1123 print_ipprot(pingpack->protocol));
1124 return 0;
1125 }
jjako5da68452003-01-28 16:08:47 +00001126
Harald Weltebed35df2011-11-02 13:06:18 +01001127 if (pingpack->type != 0) {
1128 if (!options.pingquiet)
1129 printf
1130 ("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
1131 len, inet_ntoa(src), pingpack->type,
1132 print_icmptype(pingpack->type), pingpack->code);
1133 return 0;
1134 }
jjako5da68452003-01-28 16:08:47 +00001135
Harald Weltebed35df2011-11-02 13:06:18 +01001136 nreceived++;
1137 if (!options.pingquiet)
1138 printf("%d bytes from %s: icmp_seq=%d", len,
1139 inet_ntoa(src), ntohs(pingpack->seq));
jjako5da68452003-01-28 16:08:47 +00001140
Harald Weltebed35df2011-11-02 13:06:18 +01001141 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
1142 gettimeofday(&tv, &tz);
1143 tp = (struct timeval *)pingpack->data;
1144 if ((tv.tv_usec -= tp->tv_usec) < 0) {
1145 tv.tv_sec--;
1146 tv.tv_usec += 1000000;
1147 }
1148 tv.tv_sec -= tp->tv_sec;
jjako5da68452003-01-28 16:08:47 +00001149
Harald Weltebed35df2011-11-02 13:06:18 +01001150 triptime = tv.tv_sec * 1000000 + (tv.tv_usec);
1151 tsum += triptime;
1152 if (triptime < tmin)
1153 tmin = triptime;
1154 if (triptime > tmax)
1155 tmax = triptime;
jjako5da68452003-01-28 16:08:47 +00001156
Harald Weltebed35df2011-11-02 13:06:18 +01001157 if (!options.pingquiet)
1158 printf(" time=%.3f ms\n", triptime / 1000.0);
jjako5da68452003-01-28 16:08:47 +00001159
Harald Weltebed35df2011-11-02 13:06:18 +01001160 } else if (!options.pingquiet)
1161 printf("\n");
1162 return 0;
jjako5da68452003-01-28 16:08:47 +00001163}
1164
1165/* Create a new ping packet and send it off to peer. */
1166int create_ping(void *gsn, struct pdp_t *pdp,
Harald Weltebed35df2011-11-02 13:06:18 +01001167 struct in_addr *dst, int seq, unsigned int datasize)
1168{
jjako5da68452003-01-28 16:08:47 +00001169
Harald Weltebed35df2011-11-02 13:06:18 +01001170 struct ip_ping pack;
1171 uint16_t *p = (uint16_t *) & pack;
1172 uint8_t *p8 = (uint8_t *) & pack;
1173 struct in_addr src;
1174 unsigned int n;
1175 long int sum = 0;
1176 int count = 0;
jjako5da68452003-01-28 16:08:47 +00001177
Harald Weltebed35df2011-11-02 13:06:18 +01001178 struct timezone tz;
1179 struct timeval *tp =
1180 (struct timeval *)&p8[CREATEPING_IP + CREATEPING_ICMP];
jjako5da68452003-01-28 16:08:47 +00001181
Harald Weltebed35df2011-11-02 13:06:18 +01001182 if (datasize > CREATEPING_MAX) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001183 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001184 "Ping size to large: %d!", datasize);
1185 return -1;
1186 }
jjako5da68452003-01-28 16:08:47 +00001187
Harald Weltebed35df2011-11-02 13:06:18 +01001188 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
jjako5da68452003-01-28 16:08:47 +00001189
Harald Weltebed35df2011-11-02 13:06:18 +01001190 pack.ipver = 0x45;
1191 pack.tos = 0x00;
1192 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
1193 pack.fragid = 0x0000;
1194 pack.offset = 0x0040;
1195 pack.ttl = 0x40;
1196 pack.protocol = 0x01;
1197 pack.ipcheck = 0x0000;
1198 pack.src = src.s_addr;
1199 pack.dst = dst->s_addr;
1200 pack.type = 0x08;
1201 pack.code = 0x00;
1202 pack.checksum = 0x0000;
1203 pack.ident = 0x0000;
1204 pack.seq = htons(seq);
jjako5da68452003-01-28 16:08:47 +00001205
Harald Weltebed35df2011-11-02 13:06:18 +01001206 /* Generate ICMP payload */
1207 p8 = (uint8_t *) & pack + CREATEPING_IP + CREATEPING_ICMP;
1208 for (n = 0; n < (datasize); n++)
1209 p8[n] = n;
jjako5da68452003-01-28 16:08:47 +00001210
Harald Weltebed35df2011-11-02 13:06:18 +01001211 if (datasize >= sizeof(struct timeval))
1212 gettimeofday(tp, &tz);
jjako5da68452003-01-28 16:08:47 +00001213
Harald Weltebed35df2011-11-02 13:06:18 +01001214 /* Calculate IP header checksum */
1215 p = (uint16_t *) & pack;
1216 count = CREATEPING_IP;
1217 sum = 0;
1218 while (count > 1) {
1219 sum += *p++;
1220 count -= 2;
1221 }
1222 while (sum >> 16)
1223 sum = (sum & 0xffff) + (sum >> 16);
1224 pack.ipcheck = ~sum;
jjako5da68452003-01-28 16:08:47 +00001225
Harald Weltebed35df2011-11-02 13:06:18 +01001226 /* Calculate ICMP checksum */
1227 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
1228 sum = 0;
1229 p = (uint16_t *) & pack;
1230 p += CREATEPING_IP / 2;
1231 while (count > 1) {
1232 sum += *p++;
1233 count -= 2;
1234 }
1235 if (count > 0)
1236 sum += *(unsigned char *)p;
1237 while (sum >> 16)
1238 sum = (sum & 0xffff) + (sum >> 16);
1239 pack.checksum = ~sum;
jjako5da68452003-01-28 16:08:47 +00001240
Harald Weltebed35df2011-11-02 13:06:18 +01001241 ntransmitted++;
1242 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako52c24142002-12-16 13:33:51 +00001243}
1244
Harald Weltebed35df2011-11-02 13:06:18 +01001245int delete_context(struct pdp_t *pdp)
1246{
1247
1248 if (tun && options.ipdown)
1249 tun_runscript(tun, options.ipdown);
1250
1251 ipdel((struct iphash_t *)pdp->peer);
1252 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
1253
1254 if (1 == options.contexts)
1255 state = 5; /* Disconnected */
1256
1257 return 0;
1258}
jjakoa7cd2492003-04-11 09:40:12 +00001259
1260/* Callback for receiving messages from tun */
Harald Weltebed35df2011-11-02 13:06:18 +01001261int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
1262{
1263 struct iphash_t *ipm;
1264 struct in_addr src;
1265 struct tun_packet_t *iph = (struct tun_packet_t *)pack;
jjakoa7cd2492003-04-11 09:40:12 +00001266
Harald Weltebed35df2011-11-02 13:06:18 +01001267 src.s_addr = iph->src;
jjakoa7cd2492003-04-11 09:40:12 +00001268
Harald Weltebed35df2011-11-02 13:06:18 +01001269 if (ipget(&ipm, &src)) {
1270 printf("Received packet without a valid source address!!!\n");
1271 return 0;
1272 }
1273
1274 if (ipm->pdp) /* Check if a peer protocol is defined */
1275 gtp_data_req(gsn, ipm->pdp, pack, len);
1276 return 0;
jjako52c24142002-12-16 13:33:51 +00001277}
1278
Harald Weltebed35df2011-11-02 13:06:18 +01001279int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
1280{
1281 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +00001282
Harald Weltebed35df2011-11-02 13:06:18 +01001283 struct iphash_t *iph = (struct iphash_t *)cbp;
jjako2c381332003-10-21 19:09:53 +00001284
Harald Weltebed35df2011-11-02 13:06:18 +01001285 if (cause < 0) {
1286 printf("Create PDP Context Request timed out\n");
1287 if (iph->pdp->version == 1) {
1288 printf("Retrying with version 0\n");
1289 iph->pdp->version = 0;
1290 gtp_create_context_req(gsn, iph->pdp, iph);
1291 return 0;
1292 } else {
1293 state = 0;
1294 pdp_freepdp(iph->pdp);
1295 iph->pdp = NULL;
1296 return EOF;
1297 }
1298 }
jjako2c381332003-10-21 19:09:53 +00001299
Harald Weltebed35df2011-11-02 13:06:18 +01001300 if (cause != 128) {
1301 printf
1302 ("Received create PDP context response. Cause value: %d\n",
1303 cause);
1304 state = 0;
1305 pdp_freepdp(iph->pdp);
1306 iph->pdp = NULL;
1307 return EOF; /* Not what we expected */
1308 }
jjako52c24142002-12-16 13:33:51 +00001309
Harald Weltebed35df2011-11-02 13:06:18 +01001310 if (pdp_euaton(&pdp->eua, &addr)) {
1311 printf
1312 ("Received create PDP context response. Cause value: %d\n",
1313 cause);
1314 pdp_freepdp(iph->pdp);
1315 iph->pdp = NULL;
1316 state = 0;
1317 return EOF; /* Not a valid IP address */
1318 }
jjakoa7cd2492003-04-11 09:40:12 +00001319
Harald Weltebed35df2011-11-02 13:06:18 +01001320 printf("Received create PDP context response. IP address: %s\n",
1321 inet_ntoa(addr));
jjakoa7cd2492003-04-11 09:40:12 +00001322
Harald Weltebed35df2011-11-02 13:06:18 +01001323 if ((options.createif) && (!options.net.s_addr)) {
1324 struct in_addr m;
jjakoff9985c2004-01-16 11:05:22 +00001325#ifdef HAVE_INET_ATON
Harald Weltebed35df2011-11-02 13:06:18 +01001326 inet_aton("255.255.255.255", &m);
jjako1d3db972004-01-16 09:56:56 +00001327#else
Harald Weltebed35df2011-11-02 13:06:18 +01001328 m.s_addr = -1;
jjako1d3db972004-01-16 09:56:56 +00001329#endif
Harald Weltebed35df2011-11-02 13:06:18 +01001330 /* printf("Setting up interface and routing\n"); */
1331 tun_addaddr(tun, &addr, &addr, &m);
1332 if (options.defaultroute) {
1333 struct in_addr rm;
1334 rm.s_addr = 0;
1335 tun_addroute(tun, &rm, &addr, &rm);
1336 }
1337 if (options.ipup)
1338 tun_runscript(tun, options.ipup);
1339 }
jjako52c24142002-12-16 13:33:51 +00001340
Harald Weltebed35df2011-11-02 13:06:18 +01001341 ipset((struct iphash_t *)pdp->peer, &addr);
1342
1343 state = 2; /* Connected */
1344
1345 return 0;
jjako52c24142002-12-16 13:33:51 +00001346}
1347
Harald Weltebed35df2011-11-02 13:06:18 +01001348int delete_pdp_conf(struct pdp_t *pdp, int cause)
1349{
1350 printf("Received delete PDP context response. Cause value: %d\n",
1351 cause);
1352 return 0;
jjako52c24142002-12-16 13:33:51 +00001353}
1354
Harald Weltebed35df2011-11-02 13:06:18 +01001355int echo_conf(int recovery)
1356{
jjako91aaf222003-10-22 10:09:32 +00001357
Harald Weltebed35df2011-11-02 13:06:18 +01001358 if (recovery < 0) {
1359 printf("Echo Request timed out\n");
1360 if (echoversion == 1) {
1361 printf("Retrying with version 0\n");
1362 echoversion = 0;
1363 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
1364 return 0;
1365 } else {
1366 state = 0;
1367 return EOF;
1368 }
1369 } else {
1370 printf("Received echo response\n");
1371 if (!options.contexts)
1372 state = 5;
1373 }
1374 return 0;
jjako52c24142002-12-16 13:33:51 +00001375}
1376
Harald Weltebed35df2011-11-02 13:06:18 +01001377int conf(int type, int cause, struct pdp_t *pdp, void *cbp)
1378{
1379 /* if (cause < 0) return 0; Some error occurred. We don't care */
1380 switch (type) {
1381 case GTP_ECHO_REQ:
1382 return echo_conf(cause);
1383 case GTP_CREATE_PDP_REQ:
1384 return create_pdp_conf(pdp, cbp, cause);
1385 case GTP_DELETE_PDP_REQ:
1386 if (cause != 128)
1387 return 0; /* Request not accepted. We don't care */
1388 return delete_pdp_conf(pdp, cause);
1389 default:
1390 return 0;
1391 }
jjako52c24142002-12-16 13:33:51 +00001392}
1393
Harald Weltebed35df2011-11-02 13:06:18 +01001394int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len)
1395{
1396 /* printf("encaps_tun. Packet received: forwarding to tun\n"); */
1397 return tun_encaps((struct tun_t *)pdp->ipif, pack, len);
jjako52c24142002-12-16 13:33:51 +00001398}
1399
1400int main(int argc, char **argv)
1401{
Harald Weltebed35df2011-11-02 13:06:18 +01001402 fd_set fds; /* For select() */
1403 struct timeval idleTime; /* How long to select() */
1404 struct pdp_t *pdp;
1405 int n;
1406 int starttime = time(NULL); /* Time program was started */
1407 int stoptime = 0; /* Time to exit */
1408 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +00001409
Harald Weltebed35df2011-11-02 13:06:18 +01001410 struct timezone tz; /* Used for calculating ping times */
1411 struct timeval tv;
1412 int diff;
jjako52c24142002-12-16 13:33:51 +00001413
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001414 osmo_init_logging(&log_info);
jjako0141d202004-01-09 15:19:20 +00001415
Harald Weltebed35df2011-11-02 13:06:18 +01001416 /* Process options given in configuration file and command line */
1417 if (process_options(argc, argv))
1418 exit(1);
jjako52c24142002-12-16 13:33:51 +00001419
Harald Weltebed35df2011-11-02 13:06:18 +01001420 printf("\nInitialising GTP library\n");
1421 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001422 SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create gtp");
Harald Weltebed35df2011-11-02 13:06:18 +01001423 exit(1);
1424 }
1425 if (gsn->fd0 > maxfd)
1426 maxfd = gsn->fd0;
1427 if (gsn->fd1c > maxfd)
1428 maxfd = gsn->fd1c;
1429 if (gsn->fd1u > maxfd)
1430 maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001431
Harald Weltebed35df2011-11-02 13:06:18 +01001432 gtp_set_cb_delete_context(gsn, delete_context);
1433 gtp_set_cb_conf(gsn, conf);
1434 if (options.createif)
1435 gtp_set_cb_data_ind(gsn, encaps_tun);
1436 else
1437 gtp_set_cb_data_ind(gsn, encaps_ping);
jjako52c24142002-12-16 13:33:51 +00001438
Harald Weltebed35df2011-11-02 13:06:18 +01001439 if (options.createif) {
1440 printf("Setting up interface\n");
1441 /* Create a tunnel interface */
1442 if (tun_new((struct tun_t **)&tun)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001443 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001444 "Failed to create tun");
1445 exit(1);
1446 }
1447 tun_set_cb_ind(tun, cb_tun_ind);
1448 if (tun->fd > maxfd)
1449 maxfd = tun->fd;
1450 }
jjakoa7cd2492003-04-11 09:40:12 +00001451
Harald Weltebed35df2011-11-02 13:06:18 +01001452 if ((options.createif) && (options.net.s_addr)) {
1453 /* printf("Setting up interface and routing\n"); */
1454 tun_addaddr(tun, &options.netaddr, &options.destaddr,
1455 &options.mask);
1456 if (options.defaultroute) {
1457 struct in_addr rm;
1458 rm.s_addr = 0;
1459 tun_addroute(tun, &rm, &options.destaddr, &rm);
1460 }
1461 if (options.ipup)
1462 tun_runscript(tun, options.ipup);
1463 }
jjakoa7cd2492003-04-11 09:40:12 +00001464
Harald Weltebed35df2011-11-02 13:06:18 +01001465 /* Initialise hash tables */
1466 memset(&iphash, 0, sizeof(iphash));
1467 memset(&iparr, 0, sizeof(iparr));
jjako193e8b12003-11-10 12:31:41 +00001468
Harald Weltebed35df2011-11-02 13:06:18 +01001469 printf("Done initialising GTP library\n\n");
jjako193e8b12003-11-10 12:31:41 +00001470
Harald Weltebed35df2011-11-02 13:06:18 +01001471 /* See if anybody is there */
1472 printf("Sending off echo request\n");
1473 echoversion = options.gtpversion;
1474 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjakoa7cd2492003-04-11 09:40:12 +00001475
Harald Weltebed35df2011-11-02 13:06:18 +01001476 for (n = 0; n < options.contexts; n++) {
1477 uint64_t myimsi;
1478 printf("Setting up PDP context #%d\n", n);
1479 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001480
Harald Weltebed35df2011-11-02 13:06:18 +01001481 imsi_add(options.imsi, &myimsi, n);
jjako52c24142002-12-16 13:33:51 +00001482
Harald Weltebed35df2011-11-02 13:06:18 +01001483 /* Allocated here. */
1484 /* If create context failes we have to deallocate ourselves. */
1485 /* Otherwise it is deallocated by gtplib */
1486 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjako52c24142002-12-16 13:33:51 +00001487
Harald Weltebed35df2011-11-02 13:06:18 +01001488 pdp->peer = &iparr[n];
1489 pdp->ipif = tun; /* TODO */
1490 iparr[n].pdp = pdp;
jjako193e8b12003-11-10 12:31:41 +00001491
Harald Weltebed35df2011-11-02 13:06:18 +01001492 if (options.gtpversion == 0) {
1493 if (options.qos.l - 1 > sizeof(pdp->qos_req0)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001494 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001495 "QoS length too big");
1496 exit(1);
1497 } else {
1498 memcpy(pdp->qos_req0, options.qos.v,
1499 options.qos.l);
1500 }
1501 }
jjakoa7cd2492003-04-11 09:40:12 +00001502
Harald Weltebed35df2011-11-02 13:06:18 +01001503 pdp->qos_req.l = options.qos.l;
1504 memcpy(pdp->qos_req.v, options.qos.v, options.qos.l);
jjakoa7cd2492003-04-11 09:40:12 +00001505
Harald Weltebed35df2011-11-02 13:06:18 +01001506 pdp->selmode = options.selmode;
jjako08d331d2003-10-13 20:33:30 +00001507
Harald Weltebed35df2011-11-02 13:06:18 +01001508 pdp->rattype.l = options.rattype.l;
1509 memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
1510 pdp->rattype_given = options.rattype_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001511
Harald Weltebed35df2011-11-02 13:06:18 +01001512 pdp->userloc.l = options.userloc.l;
1513 memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
1514 pdp->userloc_given = options.userloc_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001515
Harald Weltebed35df2011-11-02 13:06:18 +01001516 pdp->rai.l = options.rai.l;
1517 memcpy(pdp->rai.v, options.rai.v, options.rai.l);
1518 pdp->rai_given = options.rai_given;
Harald Welte41af5692011-10-07 18:42:34 +02001519
Harald Weltebed35df2011-11-02 13:06:18 +01001520 pdp->mstz.l = options.mstz.l;
1521 memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
1522 pdp->mstz_given = options.mstz_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001523
Harald Weltebed35df2011-11-02 13:06:18 +01001524 pdp->imeisv.l = options.imeisv.l;
1525 memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
1526 pdp->imeisv_given = options.imeisv_given;
Yann BONNAMY944dce32010-10-29 17:07:44 +02001527
Harald Weltebed35df2011-11-02 13:06:18 +01001528 pdp->norecovery_given = options.norecovery_given;
Harald Welte3a4c67b2011-10-07 18:45:54 +02001529
Harald Weltebed35df2011-11-02 13:06:18 +01001530 if (options.apn.l > sizeof(pdp->apn_use.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001531 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001532 "APN length too big");
1533 exit(1);
1534 } else {
1535 pdp->apn_use.l = options.apn.l;
1536 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1537 }
jjako193e8b12003-11-10 12:31:41 +00001538
Harald Weltebed35df2011-11-02 13:06:18 +01001539 pdp->gsnlc.l = sizeof(options.listen);
1540 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1541 pdp->gsnlu.l = sizeof(options.listen);
1542 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako08d331d2003-10-13 20:33:30 +00001543
Harald Weltebed35df2011-11-02 13:06:18 +01001544 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001545 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001546 "MSISDN length too big");
1547 exit(1);
1548 } else {
1549 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1550 }
jjakob62c3dd2004-05-27 18:51:55 +00001551
Harald Weltebed35df2011-11-02 13:06:18 +01001552 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
jjako52c24142002-12-16 13:33:51 +00001553
Harald Weltebed35df2011-11-02 13:06:18 +01001554 if (options.pco.l > sizeof(pdp->pco_req.v)) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001555 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001556 "PCO length too big");
1557 exit(1);
1558 } else {
1559 pdp->pco_req.l = options.pco.l;
1560 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1561 }
jjako52c24142002-12-16 13:33:51 +00001562
Harald Weltebed35df2011-11-02 13:06:18 +01001563 pdp->version = options.gtpversion;
jjako52c24142002-12-16 13:33:51 +00001564
Harald Weltebed35df2011-11-02 13:06:18 +01001565 pdp->hisaddr0 = options.remote;
1566 pdp->hisaddr1 = options.remote;
1567
1568 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1569 512 = Flat rate, 256 = Hot billing */
1570
1571 /* Create context */
1572 /* We send this of once. Retransmissions are handled by gtplib */
1573 gtp_create_context_req(gsn, pdp, &iparr[n]);
1574 }
1575
1576 state = 1; /* Enter wait_connection state */
1577
1578 printf("Waiting for response from ggsn........\n\n");
jjako5da68452003-01-28 16:08:47 +00001579
jjako52c24142002-12-16 13:33:51 +00001580 /******************************************************************/
Harald Weltebed35df2011-11-02 13:06:18 +01001581 /* Main select loop */
jjako52c24142002-12-16 13:33:51 +00001582 /******************************************************************/
1583
Harald Weltebed35df2011-11-02 13:06:18 +01001584 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001585
Harald Weltebed35df2011-11-02 13:06:18 +01001586 /* Take down client after timeout after disconnect */
1587 if ((4 == state) && ((stoptime) <= time(NULL))) {
1588 state = 5;
1589 }
jjako7b8fad42003-07-07 14:37:42 +00001590
Harald Weltebed35df2011-11-02 13:06:18 +01001591 /* Take down client after timelimit timeout */
1592 if ((2 == state) && (options.timelimit) &&
1593 ((starttime + options.timelimit) <= time(NULL))) {
1594 state = 3;
1595 }
jjako7b8fad42003-07-07 14:37:42 +00001596
Harald Weltebed35df2011-11-02 13:06:18 +01001597 /* Take down client after ping timeout */
1598 if ((2 == state) && (pingtimeout)
1599 && (pingtimeout <= time(NULL))) {
1600 state = 3;
1601 }
jjako7b8fad42003-07-07 14:37:42 +00001602
Harald Weltebed35df2011-11-02 13:06:18 +01001603 /* Set pingtimeout for later disconnection */
1604 if (options.pingcount && ntransmitted >= options.pingcount) {
1605 pingtimeout = time(NULL) + 5; /* Extra seconds */
1606 }
jjako7b8fad42003-07-07 14:37:42 +00001607
Harald Weltebed35df2011-11-02 13:06:18 +01001608 /* Print statistics if no more ping packets are missing */
1609 if (ntransmitted && options.pingcount
1610 && nreceived >= options.pingcount) {
1611 ping_finish();
1612 if (!options.createif)
1613 state = 3;
1614 }
jjako7b8fad42003-07-07 14:37:42 +00001615
Harald Weltebed35df2011-11-02 13:06:18 +01001616 /* Send off disconnect */
1617 if (3 == state) {
1618 state = 4;
1619 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1620 for (n = 0; n < options.contexts; n++) {
1621 /* Delete context */
1622 printf("Disconnecting PDP context #%d\n", n);
1623 gtp_delete_context_req(gsn, iparr[n].pdp, NULL,
1624 1);
1625 if ((options.pinghost.s_addr != 0)
1626 && ntransmitted)
1627 ping_finish();
1628 }
1629 }
jjako7b8fad42003-07-07 14:37:42 +00001630
Harald Weltebed35df2011-11-02 13:06:18 +01001631 /* Send of ping packets */
1632 diff = 0;
1633 while ((diff <= 0) &&
1634 /* Send off an ICMP ping packet */
1635 /*if ( */ (options.pinghost.s_addr) && (2 == state) &&
1636 ((pingseq < options.pingcount)
1637 || (options.pingcount == 0))) {
1638 if (!pingseq)
1639 gettimeofday(&firstping, &tz); /* Set time of first ping */
1640 gettimeofday(&tv, &tz);
1641 diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1642 if (diff <= 0) {
1643 if (options.debug)
1644 printf("Create_ping %d\n", diff);
1645 create_ping(gsn,
1646 iparr[pingseq %
1647 options.contexts].pdp,
1648 &options.pinghost, pingseq,
1649 options.pingsize);
1650 pingseq++;
1651 }
1652 }
jjako5da68452003-01-28 16:08:47 +00001653
Harald Weltebed35df2011-11-02 13:06:18 +01001654 FD_ZERO(&fds);
1655 if (tun)
1656 FD_SET(tun->fd, &fds);
1657 FD_SET(gsn->fd0, &fds);
1658 FD_SET(gsn->fd1c, &fds);
1659 FD_SET(gsn->fd1u, &fds);
jjako08d331d2003-10-13 20:33:30 +00001660
Harald Weltebed35df2011-11-02 13:06:18 +01001661 gtp_retranstimeout(gsn, &idleTime);
1662 ping_timeout(&idleTime);
jjako08d331d2003-10-13 20:33:30 +00001663
Harald Weltebed35df2011-11-02 13:06:18 +01001664 if (options.debug)
1665 printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1666 (int)idleTime.tv_sec, (int)idleTime.tv_usec);
jjako7b8fad42003-07-07 14:37:42 +00001667
Harald Weltebed35df2011-11-02 13:06:18 +01001668 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1669 case -1:
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001670 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001671 "Select returned -1");
1672 break;
1673 case 0:
1674 gtp_retrans(gsn); /* Only retransmit if nothing else */
1675 break;
1676 default:
1677 break;
1678 }
1679
1680 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
Holger Hans Peter Freyther9c7fd8e2014-12-04 16:32:37 +01001681 SYS_ERR(DSGSN, LOGL_ERROR, 0,
Harald Weltebed35df2011-11-02 13:06:18 +01001682 "TUN decaps failed");
1683 }
1684
1685 if (FD_ISSET(gsn->fd0, &fds))
1686 gtp_decaps0(gsn);
1687
1688 if (FD_ISSET(gsn->fd1c, &fds))
1689 gtp_decaps1c(gsn);
1690
1691 if (FD_ISSET(gsn->fd1u, &fds))
1692 gtp_decaps1u(gsn);
1693 }
1694
1695 gtp_free(gsn); /* Clean up the gsn instance */
1696
1697 if (options.createif)
1698 tun_free(tun);
1699
1700 if (0 == state)
1701 exit(1); /* Indicate error */
1702
1703 return 0;
jjako52c24142002-12-16 13:33:51 +00001704}