blob: 9099d3fd0f3d076bd317ecb7b8b5c7770db9a09f [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjakoa7cd2492003-04-11 09:40:12 +00003 * Copyright (C) 2002, 2003 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 *
10 * The initial developer of the original code is
11 * Jens Jakobsen <jj@openggsn.org>
12 *
13 * Contributor(s):
14 *
15 */
16
17/*
18 * sgsnemu.c
19 *
20 */
21
22
23#ifdef __linux__
jjakoa7cd2492003-04-11 09:40:12 +000024#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
jjako52c24142002-12-16 13:33:51 +000025#endif
26
27
28#include <syslog.h>
29#include <ctype.h>
30#include <netdb.h>
31#include <signal.h>
32#include <stdio.h>
33#include <string.h>
34#include <stdlib.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <sys/wait.h>
40#include <sys/stat.h>
41#include <unistd.h>
42#include <sys/socket.h>
43#include <sys/ioctl.h>
jjako5da68452003-01-28 16:08:47 +000044#include <sys/time.h>
jjako52c24142002-12-16 13:33:51 +000045#include <net/if.h>
jjako52c24142002-12-16 13:33:51 +000046#include <errno.h>
jjako52c24142002-12-16 13:33:51 +000047#include <sys/socket.h>
jjako52c24142002-12-16 13:33:51 +000048#include <resolv.h>
49#include <time.h>
50
51#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000052#include "ippool.h"
53#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000054#include "../gtp/pdp.h"
55#include "../gtp/gtp.h"
56#include "cmdline.h"
57
jjakoa7cd2492003-04-11 09:40:12 +000058#define IPADDRLEN 256 /* Character length of addresses */
jjako193e8b12003-11-10 12:31:41 +000059#define MAXCONTEXTS 1024 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000060
jjakoa7cd2492003-04-11 09:40:12 +000061/* HASH tables for IP address allocation */
62struct iphash_t {
63 uint8_t inuse; /* 0=free. 1=used by somebody */
64 struct iphash_t *ipnext;
65 struct pdp_t *pdp;
66 struct in_addr addr;
67};
68struct iphash_t iparr[MAXCONTEXTS];
69struct iphash_t *iphash[MAXCONTEXTS];
70
71/* State variable used for ping */
72/* 0: Idle */
73/* 1: Wait_connect */
74/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000075/* 3: Done */
76/* 4: Wait_disconnect */
77/* 5: Disconnected */
jjako581c9f02003-10-22 11:28:20 +000078int state = 0;
jjako52c24142002-12-16 13:33:51 +000079
jjakoa7cd2492003-04-11 09:40:12 +000080struct gsn_t *gsn = NULL; /* GSN instance */
81struct tun_t *tun = NULL; /* TUN instance */
jjako52c24142002-12-16 13:33:51 +000082int maxfd = 0; /* For select() */
jjako91aaf222003-10-22 10:09:32 +000083int echoversion = 1; /* First try this version */
jjako52c24142002-12-16 13:33:51 +000084
jjakoa7cd2492003-04-11 09:40:12 +000085/* Struct with local versions of gengetopt options */
86struct {
87 int debug; /* Print debug messages */
88 int createif; /* Create local network interface */
jjako193e8b12003-11-10 12:31:41 +000089 struct in_addr net, mask; /* Network interface */
jjakoa7cd2492003-04-11 09:40:12 +000090 char *ipup, *ipdown; /* Filename of scripts */
91 int defaultroute; /* Set up default route */
92 struct in_addr pinghost; /* Remote ping host */
93 int pingrate;
94 int pingsize;
95 int pingcount;
96 int pingquiet;
97 struct in_addr listen;
98 struct in_addr remote;
99 struct in_addr dns;
100 int contexts; /* Number of contexts to create */
101 int timelimit; /* Number of seconds to be connected */
102 char *statedir;
103 uint64_t imsi;
jjako193e8b12003-11-10 12:31:41 +0000104 uint8_t nsapi;
105 int gtpversion;
jjakoa7cd2492003-04-11 09:40:12 +0000106 struct ul255_t pco;
107 struct ul255_t qos;
108 struct ul255_t apn;
109 struct ul16_t msisdn;
110} options;
jjako52c24142002-12-16 13:33:51 +0000111
jjako5da68452003-01-28 16:08:47 +0000112
113/* Definitions to use for PING. Most of the ping code was derived from */
114/* the original ping program by Mike Muuss */
115
116/* IP header and ICMP echo header */
117#define CREATEPING_MAX 2048
118#define CREATEPING_IP 20
119#define CREATEPING_ICMP 8
120
121struct ip_ping {
jjako0141d202004-01-09 15:19:20 +0000122 uint8_t ipver; /* Type and header length*/
123 uint8_t tos; /* Type of Service */
124 uint16_t length; /* Total length */
125 uint16_t fragid; /* Identifier */
126 uint16_t offset; /* Flags and fragment offset */
127 uint8_t ttl; /* Time to live */
128 uint8_t protocol; /* Protocol */
129 uint16_t ipcheck; /* Header checksum */
130 uint32_t src; /* Source address */
131 uint32_t dst; /* Destination */
132 uint8_t type; /* Type and header length*/
133 uint8_t code; /* Code */
134 uint16_t checksum; /* Header checksum */
135 uint16_t ident; /* Identifier */
136 uint16_t seq; /* Sequence number */
137 uint8_t data[CREATEPING_MAX]; /* Data */
jjako5da68452003-01-28 16:08:47 +0000138} __attribute__((packed));
139
140/* Statistical values for ping */
141int nreceived = 0;
142int ntreceived = 0;
143int ntransmitted = 0;
144int tmin = 999999999;
145int tmax = 0;
146int tsum = 0;
jjakoafb2a972003-01-29 21:04:13 +0000147int pingseq = 0; /* Ping sequence counter */
148struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000149
jjakoa7cd2492003-04-11 09:40:12 +0000150int ipset(struct iphash_t *ipaddr, struct in_addr *addr) {
151 int hash = ippool_hash4(addr) % MAXCONTEXTS;
152 struct iphash_t *h;
153 struct iphash_t *prev = NULL;
154 ipaddr->ipnext = NULL;
155 ipaddr->addr.s_addr = addr->s_addr;
156 for (h = iphash[hash]; h; h = h->ipnext)
157 prev = h;
158 if (!prev)
159 iphash[hash] = ipaddr;
160 else
161 prev->ipnext = ipaddr;
162 return 0;
163}
164
165int ipdel(struct iphash_t *ipaddr) {
166 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
167 struct iphash_t *h;
168 struct iphash_t *prev = NULL;
169 for (h = iphash[hash]; h; h = h->ipnext) {
170 if (h == ipaddr) {
171 if (!prev)
172 iphash[hash] = h->ipnext;
173 else
174 prev->ipnext = h->ipnext;
175 return 0;
176 }
177 prev = h;
178 }
179 return EOF; /* End of linked list and not found */
180}
181
182int ipget(struct iphash_t **ipaddr, struct in_addr *addr) {
183 int hash = ippool_hash4(addr) % MAXCONTEXTS;
184 struct iphash_t *h;
185 for (h = iphash[hash]; h; h = h->ipnext) {
186 if ((h->addr.s_addr == addr->s_addr)) {
187 *ipaddr = h;
188 return 0;
189 }
190 }
191 return EOF; /* End of linked list and not found */
192}
193
194
195/* Used to write process ID to file. Assume someone else will delete */
196void log_pid(char *pidfile) {
197 FILE *file;
198 mode_t oldmask;
199
200 oldmask = umask(022);
201 file = fopen(pidfile, "w");
202 umask(oldmask);
203 if(!file)
204 return;
jjako0141d202004-01-09 15:19:20 +0000205 fprintf(file, "%d\n", (int) getpid());
jjakoa7cd2492003-04-11 09:40:12 +0000206 fclose(file);
207}
208
209
210int process_options(int argc, char **argv) {
211 /* gengeopt declarations */
212 struct gengetopt_args_info args_info;
213
214 struct hostent *host;
215 int n;
216
217 if (cmdline_parser (argc, argv, &args_info) != 0)
218 return -1;
219 if (args_info.debug_flag) {
220 printf("remote: %s\n", args_info.remote_arg);
221 printf("listen: %s\n", args_info.listen_arg);
222 printf("conf: %s\n", args_info.conf_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000223 printf("debug: %d\n", args_info.debug_flag);
224 printf("imsi: %s\n", args_info.imsi_arg);
225 printf("qos: %#08x\n", args_info.qos_arg);
226 printf("apn: %s\n", args_info.apn_arg);
227 printf("msisdn: %s\n", args_info.msisdn_arg);
228 printf("uid: %s\n", args_info.uid_arg);
229 printf("pwd: %s\n", args_info.pwd_arg);
230 printf("pidfile: %s\n", args_info.pidfile_arg);
231 printf("statedir: %s\n", args_info.statedir_arg);
232 printf("dns: %s\n", args_info.dns_arg);
233 printf("contexts: %d\n", args_info.contexts_arg);
234 printf("timelimit: %d\n", args_info.timelimit_arg);
235 printf("createif: %d\n", args_info.createif_flag);
236 printf("ipup: %s\n", args_info.ipup_arg);
237 printf("ipdown: %s\n", args_info.ipdown_arg);
238 printf("defaultroute: %d\n", args_info.defaultroute_flag);
239 printf("pinghost: %s\n", args_info.pinghost_arg);
240 printf("pingrate: %d\n", args_info.pingrate_arg);
241 printf("pingsize: %d\n", args_info.pingsize_arg);
242 printf("pingcount: %d\n", args_info.pingcount_arg);
243 printf("pingquiet: %d\n", args_info.pingquiet_flag);
244 }
245
246 /* Try out our new parser */
247
248 if (args_info.conf_arg) {
249 if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0) != 0)
250 return -1;
251 if (args_info.debug_flag) {
252 printf("cmdline_parser_configfile\n");
253 printf("remote: %s\n", args_info.remote_arg);
254 printf("listen: %s\n", args_info.listen_arg);
255 printf("conf: %s\n", args_info.conf_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000256 printf("debug: %d\n", args_info.debug_flag);
257 printf("imsi: %s\n", args_info.imsi_arg);
258 printf("qos: %#08x\n", args_info.qos_arg);
259 printf("apn: %s\n", args_info.apn_arg);
260 printf("msisdn: %s\n", args_info.msisdn_arg);
261 printf("uid: %s\n", args_info.uid_arg);
262 printf("pwd: %s\n", args_info.pwd_arg);
263 printf("pidfile: %s\n", args_info.pidfile_arg);
264 printf("statedir: %s\n", args_info.statedir_arg);
265 printf("dns: %s\n", args_info.dns_arg);
266 printf("contexts: %d\n", args_info.contexts_arg);
267 printf("timelimit: %d\n", args_info.timelimit_arg);
268 printf("createif: %d\n", args_info.createif_flag);
269 printf("ipup: %s\n", args_info.ipup_arg);
270 printf("ipdown: %s\n", args_info.ipdown_arg);
271 printf("defaultroute: %d\n", args_info.defaultroute_flag);
272 printf("pinghost: %s\n", args_info.pinghost_arg);
273 printf("pingrate: %d\n", args_info.pingrate_arg);
274 printf("pingsize: %d\n", args_info.pingsize_arg);
275 printf("pingcount: %d\n", args_info.pingcount_arg);
276 printf("pingquiet: %d\n", args_info.pingquiet_flag);
277 }
278 }
279
280 /* Handle each option */
281
282 /* foreground */
jjakoe607f742003-07-06 21:21:30 +0000283 /* If fg flag not given run as a daemon */
284 /* Do not allow sgsnemu to run as deamon
jjakoa7cd2492003-04-11 09:40:12 +0000285 if (!args_info.fg_flag)
286 {
287 closelog();
jjakoa7cd2492003-04-11 09:40:12 +0000288 freopen("/dev/null", "w", stdout);
289 freopen("/dev/null", "w", stderr);
290 freopen("/dev/null", "r", stdin);
291 daemon(0, 0);
jjakoa7cd2492003-04-11 09:40:12 +0000292 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
jjakoe607f742003-07-06 21:21:30 +0000293 } */
jjakoa7cd2492003-04-11 09:40:12 +0000294
295 /* debug */
296 options.debug = args_info.debug_flag;
297
298 /* pidfile */
299 /* This has to be done after we have our final pid */
300 if (args_info.pidfile_arg) {
301 log_pid(args_info.pidfile_arg);
302 }
303
304 /* dns */
305 /* If no dns option is given use system default */
306 /* Do hostname lookup to translate hostname to IP address */
307 printf("\n");
308 if (args_info.dns_arg) {
309 if (!(host = gethostbyname(args_info.dns_arg))) {
310 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
311 "Invalid DNS address: %s!", args_info.dns_arg);
312 return -1;
313 }
314 else {
315 memcpy(&options.dns.s_addr, host->h_addr, host->h_length);
316 _res.nscount = 1;
317 _res.nsaddr_list[0].sin_addr = options.dns;
318 printf("Using DNS server: %s (%s)\n",
319 args_info.dns_arg, inet_ntoa(options.dns));
320 }
321 }
322 else {
323 options.dns.s_addr= 0;
324 printf("Using default DNS server\n");
325 }
326
327 /* listen */
328 /* If no listen option is specified listen to any local port */
329 /* Do hostname lookup to translate hostname to IP address */
330 if (args_info.listen_arg) {
331 if (!(host = gethostbyname(args_info.listen_arg))) {
332 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
333 "Invalid listening address: %s!", args_info.listen_arg);
334 return -1;
335 }
336 else {
337 memcpy(&options.listen.s_addr, host->h_addr, host->h_length);
338 printf("Local IP address is: %s (%s)\n",
339 args_info.listen_arg, inet_ntoa(options.listen));
340 }
341 }
342 else {
343 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
344 "Listening address must be specified: %s!", args_info.listen_arg);
345 return -1;
346 }
347
348
349 /* remote */
350 /* If no remote option is specified terminate */
351 /* Do hostname lookup to translate hostname to IP address */
352 if (args_info.remote_arg) {
353 if (!(host = gethostbyname(args_info.remote_arg))) {
354 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
355 "Invalid remote address: %s!", args_info.remote_arg);
356 return -1;
357 }
358 else {
359 memcpy(&options.remote.s_addr, host->h_addr, host->h_length);
360 printf("Remote IP address is: %s (%s)\n",
361 args_info.remote_arg, inet_ntoa(options.remote));
362 }
363 }
364 else {
365 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
366 "No remote address given!");
367 return -1;
368 }
369
370
371 /* imsi */
372 if (strlen(args_info.imsi_arg)!=15) {
373 printf("Invalid IMSI\n");
374 return -1;
375 }
376 options.imsi = ((uint64_t) (args_info.imsi_arg[ 0]-48));
377 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4;
378 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8;
379 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12;
380 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16;
381 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20;
382 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24;
383 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28;
384 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32;
385 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36;
386 options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40;
387 options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44;
388 options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48;
389 options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52;
390 options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56;
391
jjako193e8b12003-11-10 12:31:41 +0000392 printf("IMSI is: %s (%#08llx)\n",
393 args_info.imsi_arg, options.imsi);
394
395
396 /* nsapi */
397 if ((args_info.nsapi_arg > 15) ||
398 (args_info.nsapi_arg < 0)) {
399 printf("Invalid NSAPI\n");
400 return -1;
401 }
402 options.nsapi = args_info.nsapi_arg;
403 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000404
405
406 /* qos */
407 options.qos.l = 3;
408 options.qos.v[2] = (args_info.qos_arg) & 0xff;
409 options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
410 options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
411
412 /* contexts */
413 if (args_info.contexts_arg > MAXCONTEXTS) {
414 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
415 return -1;
416 }
417 options.contexts = args_info.contexts_arg;
418
419 /* Timelimit */
420 options.timelimit = args_info.timelimit_arg;
421
jjako193e8b12003-11-10 12:31:41 +0000422 /* gtpversion */
423 if ((args_info.gtpversion_arg > 1) ||
424 (args_info.gtpversion_arg < 0)) {
425 printf("Invalid GTP version\n");
426 return -1;
427 }
428 options.gtpversion = args_info.gtpversion_arg;
429 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
430
431
jjakoa7cd2492003-04-11 09:40:12 +0000432 /* apn */
433 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
434 printf("Invalid APN\n");
435 return -1;
436 }
437 options.apn.l = strlen(args_info.apn_arg) + 1;
438 options.apn.v[0] = (char) strlen(args_info.apn_arg);
439 strncpy(&options.apn.v[1], args_info.apn_arg, sizeof(options.apn.v)-1);
440 printf("Using APN: %s\n", args_info.apn_arg);
441
442 /* msisdn */
443 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
444 printf("Invalid MSISDN\n");
445 return -1;
446 }
447 options.msisdn.l = 1;
448 options.msisdn.v[0] = 0x91; /* International format */
449 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
450 if ((n%2) == 0) {
451 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
452 options.msisdn.l += 1;
453 }
454 else {
455 options.msisdn.v[((int)n/2)+1] =
456 (options.msisdn.v[((int)n/2)+1] & 0x0f) +
457 (args_info.msisdn_arg[n] - 48) * 16;
458 }
459 }
460 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
461
462 /* UID and PWD */
463 /* Might need to also insert stuff like DNS etc. */
464 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>
465 (sizeof(options.pco.v)-1)) {
466 printf("invalid UID and PWD\n");
467 return -1;
468 }
469 options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
470 options.pco.v[0] = 0x80; /* PPP */
471 options.pco.v[1] = 0xc0; /* PAP */
472 options.pco.v[2] = 0x23;
473 options.pco.v[3] = 0x12; /* Length of protocol contents */
474 options.pco.v[4] = 0x01; /* Authenticate request */
475 options.pco.v[5] = 0x01;
476 options.pco.v[6] = 0x00; /* MSB of length */
477 options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
478 options.pco.v[8] = strlen(args_info.uid_arg);
479 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
480 options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg);
481 memcpy(&options.pco.v[10+strlen(args_info.uid_arg)],
482 args_info.pwd_arg, strlen(args_info.pwd_arg));
483
484 /* createif */
485 options.createif = args_info.createif_flag;
486
jjako193e8b12003-11-10 12:31:41 +0000487 /* net */
488 /* Store net as in_addr net and mask */
489 if (args_info.net_arg) {
490 if(ippool_aton(&options.net, &options.mask, args_info.net_arg, 0)) {
491 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
492 "Invalid network address: %s!", args_info.net_arg);
493 exit(1);
494 }
495 }
496 else {
497 options.net.s_addr = 0;
498 options.mask.s_addr = 0;
499 }
500
jjakoa7cd2492003-04-11 09:40:12 +0000501 /* ipup */
502 options.ipup = args_info.ipup_arg;
503
504 /* ipdown */
505 options.ipdown = args_info.ipdown_arg;
506
507 /* statedir */
508 options.statedir = args_info.statedir_arg;
509
510 /* defaultroute */
511 options.defaultroute = args_info.defaultroute_flag;
512
513
jjako76032b92004-01-14 06:22:08 +0000514 /* pinghost */
jjakoa7cd2492003-04-11 09:40:12 +0000515 /* Store ping host as in_addr */
516 if (args_info.pinghost_arg) {
jjako76032b92004-01-14 06:22:08 +0000517 if (!(host = gethostbyname(args_info.pinghost_arg))) {
jjakoa7cd2492003-04-11 09:40:12 +0000518 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
519 "Invalid ping host: %s!", args_info.pinghost_arg);
520 return -1;
521 }
jjako76032b92004-01-14 06:22:08 +0000522 else {
523 memcpy(&options.pinghost.s_addr, host->h_addr, host->h_length);
524 printf("Using ping host: %s (%s)\n",
525 args_info.pinghost_arg, inet_ntoa(options.pinghost));
526 }
jjakoa7cd2492003-04-11 09:40:12 +0000527 }
528
529 /* Other ping parameters */
530 options.pingrate = args_info.pingrate_arg;
531 options.pingsize = args_info.pingsize_arg;
532 options.pingcount = args_info.pingcount_arg;
533 options.pingquiet = args_info.pingquiet_flag;
534
535 return 0;
536
537}
538
jjako5da68452003-01-28 16:08:47 +0000539
540int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000541 int i;
542 printf("The packet looks like this:\n");
543 for( i=0; i<len; i++) {
jjako5da68452003-01-28 16:08:47 +0000544 printf("%02x ", (unsigned char)*(char *)(pack+i));
jjako52c24142002-12-16 13:33:51 +0000545 if (!((i+1)%16)) printf("\n");
546 };
jjako5da68452003-01-28 16:08:47 +0000547 printf("\n");
548 return 0;
jjako52c24142002-12-16 13:33:51 +0000549}
550
jjako5da68452003-01-28 16:08:47 +0000551char * print_ipprot(int t) {
552 switch (t) {
553 case 1: return "ICMP";
554 case 6: return "TCP";
555 case 17: return "UDP";
556 default: return "Unknown";
557 };
558}
559
560
561char * print_icmptype(int t) {
562 static char *ttab[] = {
563 "Echo Reply",
564 "ICMP 1",
565 "ICMP 2",
566 "Dest Unreachable",
567 "Source Quench",
568 "Redirect",
569 "ICMP 6",
570 "ICMP 7",
571 "Echo",
572 "ICMP 9",
573 "ICMP 10",
574 "Time Exceeded",
575 "Parameter Problem",
576 "Timestamp",
577 "Timestamp Reply",
578 "Info Request",
579 "Info Reply"
580 };
581 if( t < 0 || t > 16 )
582 return("OUT-OF-RANGE");
583 return(ttab[t]);
584}
585
jjako193e8b12003-11-10 12:31:41 +0000586int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add) {
587 int n;
588 uint64_t i64 = 0;
589 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
590 int msalen = 0;
591
592 /* Convert to uint64_t from ul16_t format (most significant digit first) */
593 /* ul16_t format always starts with 0x91 to indicate international format */
594 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
595 for (n=0; n< src->l; n++) {
596 if ((src->v[n] & 0x0f) != 0x0f) {
597 i64 *= 10;
598 i64 += src->v[n] & 0x0f;
599 }
600 if ((src->v[n] & 0xf0) != 0xf0) {
601 i64 *= 10;
602 i64 += (src->v[n] & 0xf0) >> 4;
603 }
604 }
605
606 i64 += add;
607
608 /* Generate array with least significant digit in first octet */
609 while (i64) {
610 msa[msalen++] = i64 % 10;
611 i64 = i64 / 10;
612 }
613
614 /* Convert back to ul16_t format */
615 for(n=0; n<msalen; n++) {
616 if ((n%2) == 0) {
617 dst->v[((int)n/2)] = msa[msalen-n-1] + 0xf0;
618 dst->l += 1;
619 }
620 else {
621 dst->v[((int)n/2)] = (dst->v[((int)n/2)] & 0x0f) +
622 msa[msalen-n-1] * 16;
623 }
624 }
625
626 return 0;
627
628}
629
630int imsi_add(uint64_t src, uint64_t *dst, int add) {
631 /* TODO: big endian / small endian ??? */
632 uint64_t i64 = 0;
633
634 /* Convert from uint64_t bcd to uint64_t integer format */
635 /* The resulting integer format is multiplied by 10 */
636 while (src) {
637 if ((src & 0x0f) != 0x0f) {
638 i64 *= 10;
639 i64 += (src & 0x0f);
640 }
641 if ((src & 0xf0) != 0xf0) {
642 i64 *= 10;
643 i64 += (src & 0xf0) >> 4;
644 }
645 src = src >> 8;
646 }
647
648 i64 += add * 10;
649
650 *dst = 0;
651 while (i64) {
652 *dst = *dst << 4;
653 *dst += (i64 % 10);
654 i64 = i64 / 10;
655 }
656
657 return 0;
658
659}
660
jjakoafb2a972003-01-29 21:04:13 +0000661/* Calculate time left until we have to send off next ping packet */
662int ping_timeout(struct timeval *tp) {
663 struct timezone tz;
664 struct timeval tv;
665 int diff;
jjakoa7cd2492003-04-11 09:40:12 +0000666 if ((options.pinghost.s_addr) && (2 == state) &&
667 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000668 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000669 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000670 1000000 * (tv.tv_sec - firstping.tv_sec) -
671 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
672 tp->tv_sec = 0;
673 if (diff > 0)
674 tp->tv_usec = diff;
jjakoa7cd2492003-04-11 09:40:12 +0000675 else {
jjakoafb2a972003-01-29 21:04:13 +0000676 /* For some reason we get packet loss if set to zero */
jjakoa7cd2492003-04-11 09:40:12 +0000677 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
678 tp->tv_usec = 0;
679 }
jjakoafb2a972003-01-29 21:04:13 +0000680 }
681 return 0;
682}
683
jjako5da68452003-01-28 16:08:47 +0000684/* Print out statistics when at the end of ping sequence */
685int ping_finish()
686{
jjakoafb2a972003-01-29 21:04:13 +0000687 struct timezone tz;
688 struct timeval tv;
689 int elapsed;
690 gettimeofday(&tv, &tz);
691 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
692 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
jjako5da68452003-01-28 16:08:47 +0000693 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000694 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
jjakoafb2a972003-01-29 21:04:13 +0000695 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
696 elapsed / 1000000.0);
jjako5da68452003-01-28 16:08:47 +0000697 printf("%d packets received, ", nreceived );
698 if (ntransmitted) {
699 if( nreceived > ntransmitted)
700 printf("-- somebody's printing up packets!");
701 else
702 printf("%d%% packet loss",
703 (int) (((ntransmitted-nreceived)*100) /
704 ntransmitted));
705 }
706 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000707 if (options.debug) printf("%d packets received in total\n", ntreceived );
jjako5da68452003-01-28 16:08:47 +0000708 if (nreceived && tsum)
709 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
710 tmin/1000.0,
711 tsum/1000.0/nreceived,
712 tmax/1000.0 );
jjakoafb2a972003-01-29 21:04:13 +0000713 printf("%d packets transmitted \n", ntreceived );
714
jjako5da68452003-01-28 16:08:47 +0000715 ntransmitted = 0;
716 return 0;
717}
718
719/* Handle a received ping packet. Print out line and update statistics. */
720int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
721 struct timezone tz;
722 struct timeval tv;
723 struct timeval *tp;
724 struct ip_ping *pingpack = pack;
725 struct in_addr src;
726 int triptime;
727
728 src.s_addr = pingpack->src;
729
730 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000731 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +0000732
733 if (len < CREATEPING_IP + CREATEPING_ICMP) {
734 printf("packet too short (%d bytes) from %s\n", len,
735 inet_ntoa(src));
736 return 0;
737 }
738
739 ntreceived++;
740 if (pingpack->protocol != 1) {
jjakoa7cd2492003-04-11 09:40:12 +0000741 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
jjako5da68452003-01-28 16:08:47 +0000742 len, inet_ntoa(src), pingpack->protocol,
743 print_ipprot(pingpack->protocol));
744 return 0;
745 }
746
747 if (pingpack->type != 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000748 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
jjako5da68452003-01-28 16:08:47 +0000749 len, inet_ntoa(src), pingpack->type,
750 print_icmptype(pingpack->type), pingpack->code);
751 return 0;
752 }
753
754 nreceived++;
jjakoa7cd2492003-04-11 09:40:12 +0000755 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
jjako5da68452003-01-28 16:08:47 +0000756 inet_ntoa(src), ntohs(pingpack->seq));
757
758 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
759 gettimeofday(&tv, &tz);
760 tp = (struct timeval *) pingpack->data;
761 if( (tv.tv_usec -= tp->tv_usec) < 0 ) {
762 tv.tv_sec--;
763 tv.tv_usec += 1000000;
764 }
765 tv.tv_sec -= tp->tv_sec;
766
767 triptime = tv.tv_sec*1000000+(tv.tv_usec);
768 tsum += triptime;
769 if( triptime < tmin )
770 tmin = triptime;
771 if( triptime > tmax )
772 tmax = triptime;
773
jjakoa7cd2492003-04-11 09:40:12 +0000774 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
jjako5da68452003-01-28 16:08:47 +0000775
776 }
777 else
jjakoa7cd2492003-04-11 09:40:12 +0000778 if (!options.pingquiet) printf("\n");
jjako5da68452003-01-28 16:08:47 +0000779 return 0;
780}
781
782/* Create a new ping packet and send it off to peer. */
783int create_ping(void *gsn, struct pdp_t *pdp,
784 struct in_addr *dst, int seq, int datasize) {
785
786 struct ip_ping pack;
jjako0141d202004-01-09 15:19:20 +0000787 uint16_t *p = (uint16_t *) &pack;
788 uint8_t *p8 = (uint8_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000789 struct in_addr src;
790 int n;
791 long int sum = 0;
792 int count = 0;
793
794 struct timezone tz;
795 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
796
797 if (datasize > CREATEPING_MAX) {
jjakoa7cd2492003-04-11 09:40:12 +0000798 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
799 "Ping size to large: %d!", datasize);
800 return -1;
jjako5da68452003-01-28 16:08:47 +0000801 }
802
803 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
804
805 pack.ipver = 0x45;
806 pack.tos = 0x00;
807 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
808 pack.fragid = 0x0000;
809 pack.offset = 0x0040;
810 pack.ttl = 0x40;
811 pack.protocol = 0x01;
812 pack.ipcheck = 0x0000;
813 pack.src = src.s_addr;
814 pack.dst = dst->s_addr;
815 pack.type = 0x08;
816 pack.code = 0x00;
817 pack.checksum = 0x0000;
818 pack.ident = 0x0000;
819 pack.seq = htons(seq);
820
821 /* Generate ICMP payload */
jjako0141d202004-01-09 15:19:20 +0000822 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
jjako5da68452003-01-28 16:08:47 +0000823 for (n=0; n<(datasize); n++) p8[n] = n;
824
825 if (datasize >= sizeof(struct timeval))
826 gettimeofday(tp, &tz);
827
828 /* Calculate IP header checksum */
jjako0141d202004-01-09 15:19:20 +0000829 p = (uint16_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000830 count = CREATEPING_IP;
831 sum = 0;
832 while (count>1) {
833 sum += *p++;
834 count -= 2;
835 }
836 while (sum>>16)
837 sum = (sum & 0xffff) + (sum >> 16);
838 pack.ipcheck = ~sum;
839
840
841 /* Calculate ICMP checksum */
842 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
843 sum = 0;
jjako0141d202004-01-09 15:19:20 +0000844 p = (uint16_t *) &pack;
jjako5da68452003-01-28 16:08:47 +0000845 p += CREATEPING_IP / 2;
846 while (count>1) {
847 sum += *p++;
848 count -= 2;
849 }
850 if (count>0)
851 sum += * (unsigned char *) p;
852 while (sum>>16)
853 sum = (sum & 0xffff) + (sum >> 16);
854 pack.checksum = ~sum;
855
856 ntransmitted++;
jjako08d331d2003-10-13 20:33:30 +0000857 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako5da68452003-01-28 16:08:47 +0000858}
859
860
jjakoa7cd2492003-04-11 09:40:12 +0000861int delete_context(struct pdp_t *pdp) {
862
863 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
864
865 ipdel((struct iphash_t*) pdp->peer);
866 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
jjako7b8fad42003-07-07 14:37:42 +0000867
868 if (1 == options.contexts)
869 state = 5; /* Disconnected */
870
jjakoa7cd2492003-04-11 09:40:12 +0000871 return 0;
jjako52c24142002-12-16 13:33:51 +0000872}
873
jjakoa7cd2492003-04-11 09:40:12 +0000874
875/* Callback for receiving messages from tun */
876int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
877 struct iphash_t *ipm;
878 struct in_addr src;
879 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
880
881 src.s_addr = iph->src;
882
883 if (ipget(&ipm, &src)) {
884 printf("Received packet without a valid source address!!!\n");
885 return 0;
jjako52c24142002-12-16 13:33:51 +0000886 }
jjako5da68452003-01-28 16:08:47 +0000887
jjakoa7cd2492003-04-11 09:40:12 +0000888 if (ipm->pdp) /* Check if a peer protocol is defined */
jjako08d331d2003-10-13 20:33:30 +0000889 gtp_data_req(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000890 return 0;
891}
892
jjako2c381332003-10-21 19:09:53 +0000893int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000894 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000895
jjako2c381332003-10-21 19:09:53 +0000896 struct iphash_t *iph = (struct iphash_t*) cbp;
897
898 if (cause < 0) {
899 printf("Create PDP Context Request timed out\n");
900 if (iph->pdp->version == 1) {
901 printf("Retrying with version 0\n");
902 iph->pdp->version = 0;
jjako193e8b12003-11-10 12:31:41 +0000903 gtp_create_context_req(gsn, iph->pdp, iph);
jjako2c381332003-10-21 19:09:53 +0000904 return 0;
905 }
906 else {
907 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000908 pdp_freepdp(iph->pdp);
909 iph->pdp = NULL;
jjako2c381332003-10-21 19:09:53 +0000910 return EOF;
911 }
912 }
913
jjakoa7cd2492003-04-11 09:40:12 +0000914 if (cause != 128) {
915 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000916 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000917 pdp_freepdp(iph->pdp);
918 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000919 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000920 }
921
jjakoa7cd2492003-04-11 09:40:12 +0000922 if (pdp_euaton(&pdp->eua, &addr)) {
923 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako0b076a32003-10-25 15:59:31 +0000924 pdp_freepdp(iph->pdp);
925 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000926 state = 0;
927 return EOF; /* Not a valid IP address */
928 }
929
930 printf("Received create PDP context response. IP address: %s\n",
931 inet_ntoa(addr));
932
jjako193e8b12003-11-10 12:31:41 +0000933 if ((options.createif) && (!options.net.s_addr)) {
jjakoa7cd2492003-04-11 09:40:12 +0000934 struct in_addr m;
jjako76032b92004-01-14 06:22:08 +0000935 inet_pton(AF_INET, "255.255.255.255", &m);
jjakoa7cd2492003-04-11 09:40:12 +0000936 /* printf("Setting up interface and routing\n");*/
937 tun_addaddr(tun, &addr, &addr, &m);
938 if (options.defaultroute) {
939 struct in_addr rm;
940 rm.s_addr = 0;
941 tun_addroute(tun, &rm, &addr, &rm);
942 }
943 if (options.ipup) tun_runscript(tun, options.ipup);
944 }
945
946 ipset((struct iphash_t*) pdp->peer, &addr);
947
948 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000949
950 return 0;
951}
952
jjako52c24142002-12-16 13:33:51 +0000953int delete_pdp_conf(struct pdp_t *pdp, int cause) {
954 printf("Received delete PDP context response. Cause value: %d\n", cause);
955 return 0;
956}
957
jjako08d331d2003-10-13 20:33:30 +0000958int echo_conf(int recovery) {
jjako91aaf222003-10-22 10:09:32 +0000959
960 if (recovery < 0) {
961 printf("Echo Request timed out\n");
962 if (echoversion == 1) {
963 printf("Retrying with version 0\n");
964 echoversion = 0;
965 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
jjako91aaf222003-10-22 10:09:32 +0000966 return 0;
967 }
968 else {
969 state = 0;
970 return EOF;
971 }
jjako7b8fad42003-07-07 14:37:42 +0000972 }
jjako581c9f02003-10-22 11:28:20 +0000973 else {
jjako08d331d2003-10-13 20:33:30 +0000974 printf("Received echo response\n");
jjako581c9f02003-10-22 11:28:20 +0000975 if (!options.contexts) state = 5;
976 }
jjako52c24142002-12-16 13:33:51 +0000977 return 0;
978}
979
jjako2c381332003-10-21 19:09:53 +0000980int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000981 /* if (cause < 0) return 0; Some error occurred. We don't care */
982 switch (type) {
983 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +0000984 return echo_conf(cause);
jjako52c24142002-12-16 13:33:51 +0000985 case GTP_CREATE_PDP_REQ:
jjako2c381332003-10-21 19:09:53 +0000986 return create_pdp_conf(pdp, cbp, cause);
jjako52c24142002-12-16 13:33:51 +0000987 case GTP_DELETE_PDP_REQ:
988 if (cause !=128) return 0; /* Request not accepted. We don't care */
989 return delete_pdp_conf(pdp, cause);
990 default:
991 return 0;
992 }
993}
994
jjako52c24142002-12-16 13:33:51 +0000995
996int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
997 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
998 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
999}
1000
1001int main(int argc, char **argv)
1002{
jjako52c24142002-12-16 13:33:51 +00001003 fd_set fds; /* For select() */
1004 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +00001005 struct pdp_t *pdp;
1006 int n;
1007 int starttime = time(NULL); /* Time program was started */
jjako7b8fad42003-07-07 14:37:42 +00001008 int stoptime = 0; /* Time to exit */
1009 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +00001010
1011 struct timezone tz; /* Used for calculating ping times */
1012 struct timeval tv;
1013 int diff;
jjako52c24142002-12-16 13:33:51 +00001014
jjako52c24142002-12-16 13:33:51 +00001015 /* open a connection to the syslog daemon */
1016 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
jjako0141d202004-01-09 15:19:20 +00001017 /* TODO: Only use LOG__PERROR for linux */
1018
1019#ifdef __linux__
jjako52c24142002-12-16 13:33:51 +00001020 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
jjako0141d202004-01-09 15:19:20 +00001021#else
1022 openlog(PACKAGE, (LOG_PID), LOG_DAEMON);
1023#endif
1024
jjako52c24142002-12-16 13:33:51 +00001025
jjakoa7cd2492003-04-11 09:40:12 +00001026 /* Process options given in configuration file and command line */
1027 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +00001028 exit(1);
jjako52c24142002-12-16 13:33:51 +00001029
1030 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +00001031 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +00001032 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1033 "Failed to create gtp");
1034 exit(1);
1035 }
jjako08d331d2003-10-13 20:33:30 +00001036 if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
1037 if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
1038 if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +00001039
jjakoa7cd2492003-04-11 09:40:12 +00001040 gtp_set_cb_delete_context(gsn, delete_context);
1041 gtp_set_cb_conf(gsn, conf);
1042 if (options.createif)
jjako08d331d2003-10-13 20:33:30 +00001043 gtp_set_cb_data_ind(gsn, encaps_tun);
jjako5da68452003-01-28 16:08:47 +00001044 else
jjako08d331d2003-10-13 20:33:30 +00001045 gtp_set_cb_data_ind(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +00001046
1047 if (options.createif) {
1048 printf("Setting up interface\n");
1049 /* Create a tunnel interface */
1050 if (tun_new((struct tun_t**) &tun)) {
1051 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1052 "Failed to create tun");
1053 exit(1);
1054 }
1055 tun_set_cb_ind(tun, cb_tun_ind);
1056 if (tun->fd > maxfd) maxfd = tun->fd;
1057 }
1058
jjako193e8b12003-11-10 12:31:41 +00001059 if ((options.createif) && (options.net.s_addr)) {
1060 /* printf("Setting up interface and routing\n");*/
1061 tun_addaddr(tun, &options.net, &options.net, &options.mask);
1062 if (options.defaultroute) {
1063 struct in_addr rm;
1064 rm.s_addr = 0;
1065 tun_addroute(tun, &rm, &options.net, &rm);
1066 }
1067 if (options.ipup) tun_runscript(tun, options.ipup);
1068 }
1069
1070
jjakoa7cd2492003-04-11 09:40:12 +00001071 /* Initialise hash tables */
1072 memset(&iphash, 0, sizeof(iphash));
1073 memset(&iparr, 0, sizeof(iparr));
1074
jjako52c24142002-12-16 13:33:51 +00001075 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +00001076
1077 /* See if anybody is there */
1078 printf("Sending off echo request\n");
jjako193e8b12003-11-10 12:31:41 +00001079 echoversion = options.gtpversion;
jjako91aaf222003-10-22 10:09:32 +00001080 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjako52c24142002-12-16 13:33:51 +00001081
jjakoa7cd2492003-04-11 09:40:12 +00001082 for(n=0; n<options.contexts; n++) {
jjako193e8b12003-11-10 12:31:41 +00001083 uint64_t myimsi;
jjako52c24142002-12-16 13:33:51 +00001084 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +00001085 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +00001086
jjako193e8b12003-11-10 12:31:41 +00001087 imsi_add(options.imsi, &myimsi, n);
1088
jjako0b076a32003-10-25 15:59:31 +00001089 /* Allocated here. */
1090 /* If create context failes we have to deallocate ourselves. */
jjako193e8b12003-11-10 12:31:41 +00001091 /* Otherwise it is deallocated by gtplib */
1092 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
jjakoa7cd2492003-04-11 09:40:12 +00001093
1094 pdp->peer = &iparr[n];
1095 pdp->ipif = tun; /* TODO */
1096 iparr[n].pdp = pdp;
1097
1098 if (options.qos.l > sizeof(pdp->qos_req0)) {
1099 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +00001100 exit(1);
1101 }
1102 else {
jjakoa7cd2492003-04-11 09:40:12 +00001103 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +00001104 }
jjako08d331d2003-10-13 20:33:30 +00001105
1106 /* TODO */
1107 pdp->qos_req.l = 4;
1108 pdp->qos_req.v[0] = 0x00;
1109 memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +00001110
jjakoa7cd2492003-04-11 09:40:12 +00001111 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +00001112
jjakoa7cd2492003-04-11 09:40:12 +00001113 if (options.apn.l > sizeof(pdp->apn_use.v)) {
1114 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +00001115 exit(1);
1116 }
1117 else {
jjakoa7cd2492003-04-11 09:40:12 +00001118 pdp->apn_use.l = options.apn.l;
1119 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +00001120 }
1121
jjakoa7cd2492003-04-11 09:40:12 +00001122 pdp->gsnlc.l = sizeof(options.listen);
1123 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1124 pdp->gsnlu.l = sizeof(options.listen);
1125 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +00001126
jjakoa7cd2492003-04-11 09:40:12 +00001127 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
1128 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +00001129 exit(1);
1130 }
1131 else {
jjako193e8b12003-11-10 12:31:41 +00001132 msisdn_add(&options.msisdn, &pdp->msisdn, n);
jjakoa7cd2492003-04-11 09:40:12 +00001133 }
1134
1135 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
1136
1137 if (options.pco.l > sizeof(pdp->pco_req.v)) {
1138 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
1139 exit(1);
1140 }
1141 else {
1142 pdp->pco_req.l = options.pco.l;
1143 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +00001144 }
1145
jjako193e8b12003-11-10 12:31:41 +00001146 pdp->version = options.gtpversion;
1147
1148 pdp->hisaddr0 = options.remote;
1149 pdp->hisaddr1 = options.remote;
jjako08d331d2003-10-13 20:33:30 +00001150
jjako52c24142002-12-16 13:33:51 +00001151 /* Create context */
1152 /* We send this of once. Retransmissions are handled by gtplib */
jjako193e8b12003-11-10 12:31:41 +00001153 gtp_create_context_req(gsn, pdp, &iparr[n]);
jjako52c24142002-12-16 13:33:51 +00001154 }
1155
1156 state = 1; /* Enter wait_connection state */
1157
1158 printf("Waiting for response from ggsn........\n\n");
1159
jjako5da68452003-01-28 16:08:47 +00001160
jjako52c24142002-12-16 13:33:51 +00001161 /******************************************************************/
1162 /* Main select loop */
1163 /******************************************************************/
1164
jjako7b8fad42003-07-07 14:37:42 +00001165 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001166
jjako7b8fad42003-07-07 14:37:42 +00001167 /* Take down client after timeout after disconnect */
1168 if ((4 == state) && ((stoptime) <= time(NULL))) {
1169 state = 5;
1170 }
1171
1172 /* Take down client after timelimit timeout */
1173 if ((2 == state) && (options.timelimit) &&
1174 ((starttime + options.timelimit) <= time(NULL))) {
jjako52c24142002-12-16 13:33:51 +00001175 state = 3;
jjako7b8fad42003-07-07 14:37:42 +00001176 }
1177
1178 /* Take down client after ping timeout */
1179 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
1180 state = 3;
1181 }
1182
1183 /* Set pingtimeout for later disconnection */
1184 if (options.pingcount && ntransmitted >= options.pingcount) {
1185 pingtimeout = time(NULL) + 5; /* Extra seconds */
1186 }
1187
1188 /* Print statistics if no more ping packets are missing */
1189 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1190 ping_finish();
1191 if (!options.createif)
1192 state = 3;
1193 }
1194
jjako2c381332003-10-21 19:09:53 +00001195 /* Send off disconnect */
jjako7b8fad42003-07-07 14:37:42 +00001196 if (3 == state) {
1197 state = 4;
1198 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
jjakoa7cd2492003-04-11 09:40:12 +00001199 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +00001200 /* Delete context */
1201 printf("Disconnecting PDP context #%d\n", n);
jjako2c381332003-10-21 19:09:53 +00001202 gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
jjakoa7cd2492003-04-11 09:40:12 +00001203 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +00001204 }
jjakoafb2a972003-01-29 21:04:13 +00001205 }
jjako7b8fad42003-07-07 14:37:42 +00001206
1207 /* Send of ping packets */
jjakoa7cd2492003-04-11 09:40:12 +00001208 diff = 0;
1209 while (( diff<=0 ) &&
jjako7b8fad42003-07-07 14:37:42 +00001210 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +00001211 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
jjako7b8fad42003-07-07 14:37:42 +00001212 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +00001213 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1214 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +00001215 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +00001216 1000000 * (tv.tv_sec - firstping.tv_sec) -
1217 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1218 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001219 if (options.debug) printf("Create_ping %d\n", diff);
1220 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1221 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001222 pingseq++;
1223 }
jjako52c24142002-12-16 13:33:51 +00001224 }
jjako5da68452003-01-28 16:08:47 +00001225
jjako52c24142002-12-16 13:33:51 +00001226 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001227 if (tun) FD_SET(tun->fd, &fds);
jjako08d331d2003-10-13 20:33:30 +00001228 FD_SET(gsn->fd0, &fds);
1229 FD_SET(gsn->fd1c, &fds);
1230 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +00001231
1232 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001233 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001234
1235 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1236 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1237
jjako52c24142002-12-16 13:33:51 +00001238 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1239 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001240 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1241 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001242 break;
1243 case 0:
1244 gtp_retrans(gsn); /* Only retransmit if nothing else */
1245 break;
1246 default:
1247 break;
1248 }
jjakoa7cd2492003-04-11 09:40:12 +00001249
1250 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1251 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1252 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001253 }
1254
jjako08d331d2003-10-13 20:33:30 +00001255 if (FD_ISSET(gsn->fd0, &fds))
1256 gtp_decaps0(gsn);
1257
1258 if (FD_ISSET(gsn->fd1c, &fds))
1259 gtp_decaps1c(gsn);
1260
1261 if (FD_ISSET(gsn->fd1u, &fds))
1262 gtp_decaps1u(gsn);
jjako5da68452003-01-28 16:08:47 +00001263 }
jjakoa7cd2492003-04-11 09:40:12 +00001264
jjako52c24142002-12-16 13:33:51 +00001265 gtp_free(gsn); /* Clean up the gsn instance */
1266
jjakoa7cd2492003-04-11 09:40:12 +00001267 if (options.createif)
1268 tun_free(tun);
jjako7b8fad42003-07-07 14:37:42 +00001269
1270 if (0 == state)
1271 exit(1); /* Indicate error */
jjako52c24142002-12-16 13:33:51 +00001272
jjakoa7cd2492003-04-11 09:40:12 +00001273 return 0;
jjako52c24142002-12-16 13:33:51 +00001274}
1275