blob: 7974a9057d4ba15357caba23281a19f3a213de3b [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>
46#include <features.h>
47#include <errno.h>
48#include <asm/types.h>
49#include <sys/socket.h>
50#include <linux/netlink.h>
51#include <resolv.h>
52#include <time.h>
53
54#include "tun.h"
jjakoa7cd2492003-04-11 09:40:12 +000055#include "ippool.h"
56#include "syserr.h"
jjako52c24142002-12-16 13:33:51 +000057#include "../gtp/pdp.h"
58#include "../gtp/gtp.h"
59#include "cmdline.h"
60
jjakoa7cd2492003-04-11 09:40:12 +000061#define IPADDRLEN 256 /* Character length of addresses */
62#define MAXCONTEXTS 16 /* Max number of allowed contexts */
jjako5da68452003-01-28 16:08:47 +000063
jjakoa7cd2492003-04-11 09:40:12 +000064/* HASH tables for IP address allocation */
65struct iphash_t {
66 uint8_t inuse; /* 0=free. 1=used by somebody */
67 struct iphash_t *ipnext;
68 struct pdp_t *pdp;
69 struct in_addr addr;
70};
71struct iphash_t iparr[MAXCONTEXTS];
72struct iphash_t *iphash[MAXCONTEXTS];
73
74/* State variable used for ping */
75/* 0: Idle */
76/* 1: Wait_connect */
77/* 2: Connected */
jjako7b8fad42003-07-07 14:37:42 +000078/* 3: Done */
79/* 4: Wait_disconnect */
80/* 5: Disconnected */
jjako52c24142002-12-16 13:33:51 +000081int state = 0;
82
jjakoa7cd2492003-04-11 09:40:12 +000083struct gsn_t *gsn = NULL; /* GSN instance */
84struct tun_t *tun = NULL; /* TUN instance */
jjako52c24142002-12-16 13:33:51 +000085int maxfd = 0; /* For select() */
jjako52c24142002-12-16 13:33:51 +000086
jjakoa7cd2492003-04-11 09:40:12 +000087/* Struct with local versions of gengetopt options */
88struct {
89 int debug; /* Print debug messages */
90 int createif; /* Create local network interface */
91 char *ipup, *ipdown; /* Filename of scripts */
92 int defaultroute; /* Set up default route */
93 struct in_addr pinghost; /* Remote ping host */
94 int pingrate;
95 int pingsize;
96 int pingcount;
97 int pingquiet;
98 struct in_addr listen;
99 struct in_addr remote;
100 struct in_addr dns;
101 int contexts; /* Number of contexts to create */
102 int timelimit; /* Number of seconds to be connected */
103 char *statedir;
104 uint64_t imsi;
105 struct ul255_t pco;
106 struct ul255_t qos;
107 struct ul255_t apn;
108 struct ul16_t msisdn;
109} options;
jjako52c24142002-12-16 13:33:51 +0000110
jjako5da68452003-01-28 16:08:47 +0000111
112/* Definitions to use for PING. Most of the ping code was derived from */
113/* the original ping program by Mike Muuss */
114
115/* IP header and ICMP echo header */
116#define CREATEPING_MAX 2048
117#define CREATEPING_IP 20
118#define CREATEPING_ICMP 8
119
120struct ip_ping {
121 u_int8_t ipver; /* Type and header length*/
122 u_int8_t tos; /* Type of Service */
123 u_int16_t length; /* Total length */
124 u_int16_t fragid; /* Identifier */
125 u_int16_t offset; /* Flags and fragment offset */
126 u_int8_t ttl; /* Time to live */
127 u_int8_t protocol; /* Protocol */
128 u_int16_t ipcheck; /* Header checksum */
129 u_int32_t src; /* Source address */
130 u_int32_t dst; /* Destination */
131 u_int8_t type; /* Type and header length*/
132 u_int8_t code; /* Code */
133 u_int16_t checksum; /* Header checksum */
134 u_int16_t ident; /* Identifier */
135 u_int16_t seq; /* Sequence number */
136 u_int8_t data[CREATEPING_MAX]; /* Data */
137} __attribute__((packed));
138
139/* Statistical values for ping */
140int nreceived = 0;
141int ntreceived = 0;
142int ntransmitted = 0;
143int tmin = 999999999;
144int tmax = 0;
145int tsum = 0;
jjakoafb2a972003-01-29 21:04:13 +0000146int pingseq = 0; /* Ping sequence counter */
147struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000148
jjakoa7cd2492003-04-11 09:40:12 +0000149int ipset(struct iphash_t *ipaddr, struct in_addr *addr) {
150 int hash = ippool_hash4(addr) % MAXCONTEXTS;
151 struct iphash_t *h;
152 struct iphash_t *prev = NULL;
153 ipaddr->ipnext = NULL;
154 ipaddr->addr.s_addr = addr->s_addr;
155 for (h = iphash[hash]; h; h = h->ipnext)
156 prev = h;
157 if (!prev)
158 iphash[hash] = ipaddr;
159 else
160 prev->ipnext = ipaddr;
161 return 0;
162}
163
164int ipdel(struct iphash_t *ipaddr) {
165 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
166 struct iphash_t *h;
167 struct iphash_t *prev = NULL;
168 for (h = iphash[hash]; h; h = h->ipnext) {
169 if (h == ipaddr) {
170 if (!prev)
171 iphash[hash] = h->ipnext;
172 else
173 prev->ipnext = h->ipnext;
174 return 0;
175 }
176 prev = h;
177 }
178 return EOF; /* End of linked list and not found */
179}
180
181int ipget(struct iphash_t **ipaddr, struct in_addr *addr) {
182 int hash = ippool_hash4(addr) % MAXCONTEXTS;
183 struct iphash_t *h;
184 for (h = iphash[hash]; h; h = h->ipnext) {
185 if ((h->addr.s_addr == addr->s_addr)) {
186 *ipaddr = h;
187 return 0;
188 }
189 }
190 return EOF; /* End of linked list and not found */
191}
192
193
194/* Used to write process ID to file. Assume someone else will delete */
195void log_pid(char *pidfile) {
196 FILE *file;
197 mode_t oldmask;
198
199 oldmask = umask(022);
200 file = fopen(pidfile, "w");
201 umask(oldmask);
202 if(!file)
203 return;
204 fprintf(file, "%d\n", getpid());
205 fclose(file);
206}
207
208
209int process_options(int argc, char **argv) {
210 /* gengeopt declarations */
211 struct gengetopt_args_info args_info;
212
213 struct hostent *host;
214 int n;
215
216 if (cmdline_parser (argc, argv, &args_info) != 0)
217 return -1;
218 if (args_info.debug_flag) {
219 printf("remote: %s\n", args_info.remote_arg);
220 printf("listen: %s\n", args_info.listen_arg);
221 printf("conf: %s\n", args_info.conf_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000222 printf("debug: %d\n", args_info.debug_flag);
223 printf("imsi: %s\n", args_info.imsi_arg);
224 printf("qos: %#08x\n", args_info.qos_arg);
225 printf("apn: %s\n", args_info.apn_arg);
226 printf("msisdn: %s\n", args_info.msisdn_arg);
227 printf("uid: %s\n", args_info.uid_arg);
228 printf("pwd: %s\n", args_info.pwd_arg);
229 printf("pidfile: %s\n", args_info.pidfile_arg);
230 printf("statedir: %s\n", args_info.statedir_arg);
231 printf("dns: %s\n", args_info.dns_arg);
232 printf("contexts: %d\n", args_info.contexts_arg);
233 printf("timelimit: %d\n", args_info.timelimit_arg);
234 printf("createif: %d\n", args_info.createif_flag);
235 printf("ipup: %s\n", args_info.ipup_arg);
236 printf("ipdown: %s\n", args_info.ipdown_arg);
237 printf("defaultroute: %d\n", args_info.defaultroute_flag);
238 printf("pinghost: %s\n", args_info.pinghost_arg);
239 printf("pingrate: %d\n", args_info.pingrate_arg);
240 printf("pingsize: %d\n", args_info.pingsize_arg);
241 printf("pingcount: %d\n", args_info.pingcount_arg);
242 printf("pingquiet: %d\n", args_info.pingquiet_flag);
243 }
244
245 /* Try out our new parser */
246
247 if (args_info.conf_arg) {
248 if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0) != 0)
249 return -1;
250 if (args_info.debug_flag) {
251 printf("cmdline_parser_configfile\n");
252 printf("remote: %s\n", args_info.remote_arg);
253 printf("listen: %s\n", args_info.listen_arg);
254 printf("conf: %s\n", args_info.conf_arg);
jjakoa7cd2492003-04-11 09:40:12 +0000255 printf("debug: %d\n", args_info.debug_flag);
256 printf("imsi: %s\n", args_info.imsi_arg);
257 printf("qos: %#08x\n", args_info.qos_arg);
258 printf("apn: %s\n", args_info.apn_arg);
259 printf("msisdn: %s\n", args_info.msisdn_arg);
260 printf("uid: %s\n", args_info.uid_arg);
261 printf("pwd: %s\n", args_info.pwd_arg);
262 printf("pidfile: %s\n", args_info.pidfile_arg);
263 printf("statedir: %s\n", args_info.statedir_arg);
264 printf("dns: %s\n", args_info.dns_arg);
265 printf("contexts: %d\n", args_info.contexts_arg);
266 printf("timelimit: %d\n", args_info.timelimit_arg);
267 printf("createif: %d\n", args_info.createif_flag);
268 printf("ipup: %s\n", args_info.ipup_arg);
269 printf("ipdown: %s\n", args_info.ipdown_arg);
270 printf("defaultroute: %d\n", args_info.defaultroute_flag);
271 printf("pinghost: %s\n", args_info.pinghost_arg);
272 printf("pingrate: %d\n", args_info.pingrate_arg);
273 printf("pingsize: %d\n", args_info.pingsize_arg);
274 printf("pingcount: %d\n", args_info.pingcount_arg);
275 printf("pingquiet: %d\n", args_info.pingquiet_flag);
276 }
277 }
278
279 /* Handle each option */
280
281 /* foreground */
jjakoe607f742003-07-06 21:21:30 +0000282 /* If fg flag not given run as a daemon */
283 /* Do not allow sgsnemu to run as deamon
jjakoa7cd2492003-04-11 09:40:12 +0000284 if (!args_info.fg_flag)
285 {
286 closelog();
jjakoa7cd2492003-04-11 09:40:12 +0000287 freopen("/dev/null", "w", stdout);
288 freopen("/dev/null", "w", stderr);
289 freopen("/dev/null", "r", stdin);
290 daemon(0, 0);
jjakoa7cd2492003-04-11 09:40:12 +0000291 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
jjakoe607f742003-07-06 21:21:30 +0000292 } */
jjakoa7cd2492003-04-11 09:40:12 +0000293
294 /* debug */
295 options.debug = args_info.debug_flag;
296
297 /* pidfile */
298 /* This has to be done after we have our final pid */
299 if (args_info.pidfile_arg) {
300 log_pid(args_info.pidfile_arg);
301 }
302
303 /* dns */
304 /* If no dns option is given use system default */
305 /* Do hostname lookup to translate hostname to IP address */
306 printf("\n");
307 if (args_info.dns_arg) {
308 if (!(host = gethostbyname(args_info.dns_arg))) {
309 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
310 "Invalid DNS address: %s!", args_info.dns_arg);
311 return -1;
312 }
313 else {
314 memcpy(&options.dns.s_addr, host->h_addr, host->h_length);
315 _res.nscount = 1;
316 _res.nsaddr_list[0].sin_addr = options.dns;
317 printf("Using DNS server: %s (%s)\n",
318 args_info.dns_arg, inet_ntoa(options.dns));
319 }
320 }
321 else {
322 options.dns.s_addr= 0;
323 printf("Using default DNS server\n");
324 }
325
326 /* listen */
327 /* If no listen option is specified listen to any local port */
328 /* Do hostname lookup to translate hostname to IP address */
329 if (args_info.listen_arg) {
330 if (!(host = gethostbyname(args_info.listen_arg))) {
331 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
332 "Invalid listening address: %s!", args_info.listen_arg);
333 return -1;
334 }
335 else {
336 memcpy(&options.listen.s_addr, host->h_addr, host->h_length);
337 printf("Local IP address is: %s (%s)\n",
338 args_info.listen_arg, inet_ntoa(options.listen));
339 }
340 }
341 else {
342 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
343 "Listening address must be specified: %s!", args_info.listen_arg);
344 return -1;
345 }
346
347
348 /* remote */
349 /* If no remote option is specified terminate */
350 /* Do hostname lookup to translate hostname to IP address */
351 if (args_info.remote_arg) {
352 if (!(host = gethostbyname(args_info.remote_arg))) {
353 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
354 "Invalid remote address: %s!", args_info.remote_arg);
355 return -1;
356 }
357 else {
358 memcpy(&options.remote.s_addr, host->h_addr, host->h_length);
359 printf("Remote IP address is: %s (%s)\n",
360 args_info.remote_arg, inet_ntoa(options.remote));
361 }
362 }
363 else {
364 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
365 "No remote address given!");
366 return -1;
367 }
368
369
370 /* imsi */
371 if (strlen(args_info.imsi_arg)!=15) {
372 printf("Invalid IMSI\n");
373 return -1;
374 }
375 options.imsi = ((uint64_t) (args_info.imsi_arg[ 0]-48));
376 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4;
377 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8;
378 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12;
379 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16;
380 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20;
381 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24;
382 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28;
383 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32;
384 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36;
385 options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40;
386 options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44;
387 options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48;
388 options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52;
389 options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56;
390
391 printf("IMSI is: %s (%#08llx)\n",
392 args_info.imsi_arg, options.imsi);
393
394
395 /* qos */
396 options.qos.l = 3;
397 options.qos.v[2] = (args_info.qos_arg) & 0xff;
398 options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
399 options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
400
401 /* contexts */
402 if (args_info.contexts_arg > MAXCONTEXTS) {
403 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
404 return -1;
405 }
406 options.contexts = args_info.contexts_arg;
407
408 /* Timelimit */
409 options.timelimit = args_info.timelimit_arg;
410
411 /* apn */
412 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
413 printf("Invalid APN\n");
414 return -1;
415 }
416 options.apn.l = strlen(args_info.apn_arg) + 1;
417 options.apn.v[0] = (char) strlen(args_info.apn_arg);
418 strncpy(&options.apn.v[1], args_info.apn_arg, sizeof(options.apn.v)-1);
419 printf("Using APN: %s\n", args_info.apn_arg);
420
421 /* msisdn */
422 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
423 printf("Invalid MSISDN\n");
424 return -1;
425 }
426 options.msisdn.l = 1;
427 options.msisdn.v[0] = 0x91; /* International format */
428 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
429 if ((n%2) == 0) {
430 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
431 options.msisdn.l += 1;
432 }
433 else {
434 options.msisdn.v[((int)n/2)+1] =
435 (options.msisdn.v[((int)n/2)+1] & 0x0f) +
436 (args_info.msisdn_arg[n] - 48) * 16;
437 }
438 }
439 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
440
441 /* UID and PWD */
442 /* Might need to also insert stuff like DNS etc. */
443 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>
444 (sizeof(options.pco.v)-1)) {
445 printf("invalid UID and PWD\n");
446 return -1;
447 }
448 options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
449 options.pco.v[0] = 0x80; /* PPP */
450 options.pco.v[1] = 0xc0; /* PAP */
451 options.pco.v[2] = 0x23;
452 options.pco.v[3] = 0x12; /* Length of protocol contents */
453 options.pco.v[4] = 0x01; /* Authenticate request */
454 options.pco.v[5] = 0x01;
455 options.pco.v[6] = 0x00; /* MSB of length */
456 options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
457 options.pco.v[8] = strlen(args_info.uid_arg);
458 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
459 options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg);
460 memcpy(&options.pco.v[10+strlen(args_info.uid_arg)],
461 args_info.pwd_arg, strlen(args_info.pwd_arg));
462
463 /* createif */
464 options.createif = args_info.createif_flag;
465
466 /* ipup */
467 options.ipup = args_info.ipup_arg;
468
469 /* ipdown */
470 options.ipdown = args_info.ipdown_arg;
471
472 /* statedir */
473 options.statedir = args_info.statedir_arg;
474
475 /* defaultroute */
476 options.defaultroute = args_info.defaultroute_flag;
477
478
479 /* pinghost */
480 /* Store ping host as in_addr */
481 if (args_info.pinghost_arg) {
482 if (!inet_aton(args_info.pinghost_arg, &options.pinghost)) {
483 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
484 "Invalid ping host: %s!", args_info.pinghost_arg);
485 return -1;
486 }
487 }
488
489 /* Other ping parameters */
490 options.pingrate = args_info.pingrate_arg;
491 options.pingsize = args_info.pingsize_arg;
492 options.pingcount = args_info.pingcount_arg;
493 options.pingquiet = args_info.pingquiet_flag;
494
495 return 0;
496
497}
498
jjako5da68452003-01-28 16:08:47 +0000499
500int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000501 int i;
502 printf("The packet looks like this:\n");
503 for( i=0; i<len; i++) {
jjako5da68452003-01-28 16:08:47 +0000504 printf("%02x ", (unsigned char)*(char *)(pack+i));
jjako52c24142002-12-16 13:33:51 +0000505 if (!((i+1)%16)) printf("\n");
506 };
jjako5da68452003-01-28 16:08:47 +0000507 printf("\n");
508 return 0;
jjako52c24142002-12-16 13:33:51 +0000509}
510
jjako5da68452003-01-28 16:08:47 +0000511char * print_ipprot(int t) {
512 switch (t) {
513 case 1: return "ICMP";
514 case 6: return "TCP";
515 case 17: return "UDP";
516 default: return "Unknown";
517 };
518}
519
520
521char * print_icmptype(int t) {
522 static char *ttab[] = {
523 "Echo Reply",
524 "ICMP 1",
525 "ICMP 2",
526 "Dest Unreachable",
527 "Source Quench",
528 "Redirect",
529 "ICMP 6",
530 "ICMP 7",
531 "Echo",
532 "ICMP 9",
533 "ICMP 10",
534 "Time Exceeded",
535 "Parameter Problem",
536 "Timestamp",
537 "Timestamp Reply",
538 "Info Request",
539 "Info Reply"
540 };
541 if( t < 0 || t > 16 )
542 return("OUT-OF-RANGE");
543 return(ttab[t]);
544}
545
jjakoafb2a972003-01-29 21:04:13 +0000546/* Calculate time left until we have to send off next ping packet */
547int ping_timeout(struct timeval *tp) {
548 struct timezone tz;
549 struct timeval tv;
550 int diff;
jjakoa7cd2492003-04-11 09:40:12 +0000551 if ((options.pinghost.s_addr) && (2 == state) &&
552 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000553 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000554 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000555 1000000 * (tv.tv_sec - firstping.tv_sec) -
556 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
557 tp->tv_sec = 0;
558 if (diff > 0)
559 tp->tv_usec = diff;
jjakoa7cd2492003-04-11 09:40:12 +0000560 else {
jjakoafb2a972003-01-29 21:04:13 +0000561 /* For some reason we get packet loss if set to zero */
jjakoa7cd2492003-04-11 09:40:12 +0000562 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
563 tp->tv_usec = 0;
564 }
jjakoafb2a972003-01-29 21:04:13 +0000565 }
566 return 0;
567}
568
jjako5da68452003-01-28 16:08:47 +0000569/* Print out statistics when at the end of ping sequence */
570int ping_finish()
571{
jjakoafb2a972003-01-29 21:04:13 +0000572 struct timezone tz;
573 struct timeval tv;
574 int elapsed;
575 gettimeofday(&tv, &tz);
576 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
577 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
jjako5da68452003-01-28 16:08:47 +0000578 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000579 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
jjakoafb2a972003-01-29 21:04:13 +0000580 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
581 elapsed / 1000000.0);
jjako5da68452003-01-28 16:08:47 +0000582 printf("%d packets received, ", nreceived );
583 if (ntransmitted) {
584 if( nreceived > ntransmitted)
585 printf("-- somebody's printing up packets!");
586 else
587 printf("%d%% packet loss",
588 (int) (((ntransmitted-nreceived)*100) /
589 ntransmitted));
590 }
591 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000592 if (options.debug) printf("%d packets received in total\n", ntreceived );
jjako5da68452003-01-28 16:08:47 +0000593 if (nreceived && tsum)
594 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
595 tmin/1000.0,
596 tsum/1000.0/nreceived,
597 tmax/1000.0 );
jjakoafb2a972003-01-29 21:04:13 +0000598 printf("%d packets transmitted \n", ntreceived );
599
jjako5da68452003-01-28 16:08:47 +0000600 ntransmitted = 0;
601 return 0;
602}
603
604/* Handle a received ping packet. Print out line and update statistics. */
605int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
606 struct timezone tz;
607 struct timeval tv;
608 struct timeval *tp;
609 struct ip_ping *pingpack = pack;
610 struct in_addr src;
611 int triptime;
612
613 src.s_addr = pingpack->src;
614
615 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000616 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +0000617
618 if (len < CREATEPING_IP + CREATEPING_ICMP) {
619 printf("packet too short (%d bytes) from %s\n", len,
620 inet_ntoa(src));
621 return 0;
622 }
623
624 ntreceived++;
625 if (pingpack->protocol != 1) {
jjakoa7cd2492003-04-11 09:40:12 +0000626 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
jjako5da68452003-01-28 16:08:47 +0000627 len, inet_ntoa(src), pingpack->protocol,
628 print_ipprot(pingpack->protocol));
629 return 0;
630 }
631
632 if (pingpack->type != 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000633 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
jjako5da68452003-01-28 16:08:47 +0000634 len, inet_ntoa(src), pingpack->type,
635 print_icmptype(pingpack->type), pingpack->code);
636 return 0;
637 }
638
639 nreceived++;
jjakoa7cd2492003-04-11 09:40:12 +0000640 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
jjako5da68452003-01-28 16:08:47 +0000641 inet_ntoa(src), ntohs(pingpack->seq));
642
643 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
644 gettimeofday(&tv, &tz);
645 tp = (struct timeval *) pingpack->data;
646 if( (tv.tv_usec -= tp->tv_usec) < 0 ) {
647 tv.tv_sec--;
648 tv.tv_usec += 1000000;
649 }
650 tv.tv_sec -= tp->tv_sec;
651
652 triptime = tv.tv_sec*1000000+(tv.tv_usec);
653 tsum += triptime;
654 if( triptime < tmin )
655 tmin = triptime;
656 if( triptime > tmax )
657 tmax = triptime;
658
jjakoa7cd2492003-04-11 09:40:12 +0000659 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
jjako5da68452003-01-28 16:08:47 +0000660
661 }
662 else
jjakoa7cd2492003-04-11 09:40:12 +0000663 if (!options.pingquiet) printf("\n");
jjako5da68452003-01-28 16:08:47 +0000664 return 0;
665}
666
667/* Create a new ping packet and send it off to peer. */
668int create_ping(void *gsn, struct pdp_t *pdp,
669 struct in_addr *dst, int seq, int datasize) {
670
671 struct ip_ping pack;
672 u_int16_t *p = (u_int16_t *) &pack;
673 u_int8_t *p8 = (u_int8_t *) &pack;
674 struct in_addr src;
675 int n;
676 long int sum = 0;
677 int count = 0;
678
679 struct timezone tz;
680 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
681
682 if (datasize > CREATEPING_MAX) {
jjakoa7cd2492003-04-11 09:40:12 +0000683 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
684 "Ping size to large: %d!", datasize);
685 return -1;
jjako5da68452003-01-28 16:08:47 +0000686 }
687
688 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
689
690 pack.ipver = 0x45;
691 pack.tos = 0x00;
692 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
693 pack.fragid = 0x0000;
694 pack.offset = 0x0040;
695 pack.ttl = 0x40;
696 pack.protocol = 0x01;
697 pack.ipcheck = 0x0000;
698 pack.src = src.s_addr;
699 pack.dst = dst->s_addr;
700 pack.type = 0x08;
701 pack.code = 0x00;
702 pack.checksum = 0x0000;
703 pack.ident = 0x0000;
704 pack.seq = htons(seq);
705
706 /* Generate ICMP payload */
707 p8 = (u_int8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
708 for (n=0; n<(datasize); n++) p8[n] = n;
709
710 if (datasize >= sizeof(struct timeval))
711 gettimeofday(tp, &tz);
712
713 /* Calculate IP header checksum */
714 p = (u_int16_t *) &pack;
715 count = CREATEPING_IP;
716 sum = 0;
717 while (count>1) {
718 sum += *p++;
719 count -= 2;
720 }
721 while (sum>>16)
722 sum = (sum & 0xffff) + (sum >> 16);
723 pack.ipcheck = ~sum;
724
725
726 /* Calculate ICMP checksum */
727 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
728 sum = 0;
729 p = (u_int16_t *) &pack;
730 p += CREATEPING_IP / 2;
731 while (count>1) {
732 sum += *p++;
733 count -= 2;
734 }
735 if (count>0)
736 sum += * (unsigned char *) p;
737 while (sum>>16)
738 sum = (sum & 0xffff) + (sum >> 16);
739 pack.checksum = ~sum;
740
741 ntransmitted++;
jjako08d331d2003-10-13 20:33:30 +0000742 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako5da68452003-01-28 16:08:47 +0000743}
744
745
jjakoa7cd2492003-04-11 09:40:12 +0000746int delete_context(struct pdp_t *pdp) {
747
748 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
749
750 ipdel((struct iphash_t*) pdp->peer);
751 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
jjako7b8fad42003-07-07 14:37:42 +0000752
753 if (1 == options.contexts)
754 state = 5; /* Disconnected */
755
jjakoa7cd2492003-04-11 09:40:12 +0000756 return 0;
jjako52c24142002-12-16 13:33:51 +0000757}
758
jjakoa7cd2492003-04-11 09:40:12 +0000759
760/* Callback for receiving messages from tun */
761int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
762 struct iphash_t *ipm;
763 struct in_addr src;
764 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
765
766 src.s_addr = iph->src;
767
768 if (ipget(&ipm, &src)) {
769 printf("Received packet without a valid source address!!!\n");
770 return 0;
jjako52c24142002-12-16 13:33:51 +0000771 }
jjako5da68452003-01-28 16:08:47 +0000772
jjakoa7cd2492003-04-11 09:40:12 +0000773 if (ipm->pdp) /* Check if a peer protocol is defined */
jjako08d331d2003-10-13 20:33:30 +0000774 gtp_data_req(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000775 return 0;
776}
777
jjako2c381332003-10-21 19:09:53 +0000778int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000779 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000780
jjako2c381332003-10-21 19:09:53 +0000781 struct iphash_t *iph = (struct iphash_t*) cbp;
782
783 if (cause < 0) {
784 printf("Create PDP Context Request timed out\n");
785 if (iph->pdp->version == 1) {
786 printf("Retrying with version 0\n");
787 iph->pdp->version = 0;
788 gtp_create_context_req(gsn, iph->pdp, iph, &options.remote);
789 state = 1; /* Enter wait_connection state */
790 return 0;
791 }
792 else {
793 state = 0;
794 return EOF;
795 }
796 }
797
jjakoa7cd2492003-04-11 09:40:12 +0000798 if (cause != 128) {
799 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000800 state = 0;
jjakoa7cd2492003-04-11 09:40:12 +0000801 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000802 }
803
jjakoa7cd2492003-04-11 09:40:12 +0000804 if (pdp_euaton(&pdp->eua, &addr)) {
805 printf("Received create PDP context response. Cause value: %d\n", cause);
806 state = 0;
807 return EOF; /* Not a valid IP address */
808 }
809
810 printf("Received create PDP context response. IP address: %s\n",
811 inet_ntoa(addr));
812
813 if (options.createif) {
814 struct in_addr m;
815 inet_aton("255.255.255.255", &m);
816 /* printf("Setting up interface and routing\n");*/
817 tun_addaddr(tun, &addr, &addr, &m);
818 if (options.defaultroute) {
819 struct in_addr rm;
820 rm.s_addr = 0;
821 tun_addroute(tun, &rm, &addr, &rm);
822 }
823 if (options.ipup) tun_runscript(tun, options.ipup);
824 }
825
826 ipset((struct iphash_t*) pdp->peer, &addr);
827
828 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000829
830 return 0;
831}
832
jjako52c24142002-12-16 13:33:51 +0000833int delete_pdp_conf(struct pdp_t *pdp, int cause) {
834 printf("Received delete PDP context response. Cause value: %d\n", cause);
835 return 0;
836}
837
jjako08d331d2003-10-13 20:33:30 +0000838int echo_conf(int recovery) {
839 if (recovery <0) {
jjako5da68452003-01-28 16:08:47 +0000840 printf("Echo request timed out\n");
jjako7b8fad42003-07-07 14:37:42 +0000841 state = 0;
842 }
jjako5da68452003-01-28 16:08:47 +0000843 else
jjako08d331d2003-10-13 20:33:30 +0000844 printf("Received echo response\n");
jjako52c24142002-12-16 13:33:51 +0000845 return 0;
846}
847
jjako2c381332003-10-21 19:09:53 +0000848int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000849 /* if (cause < 0) return 0; Some error occurred. We don't care */
850 switch (type) {
851 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +0000852 return echo_conf(cause);
jjako52c24142002-12-16 13:33:51 +0000853 case GTP_CREATE_PDP_REQ:
jjako2c381332003-10-21 19:09:53 +0000854 return create_pdp_conf(pdp, cbp, cause);
jjako52c24142002-12-16 13:33:51 +0000855 case GTP_DELETE_PDP_REQ:
856 if (cause !=128) return 0; /* Request not accepted. We don't care */
857 return delete_pdp_conf(pdp, cause);
858 default:
859 return 0;
860 }
861}
862
jjako52c24142002-12-16 13:33:51 +0000863
864int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
865 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
866 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
867}
868
869int main(int argc, char **argv)
870{
jjako52c24142002-12-16 13:33:51 +0000871 fd_set fds; /* For select() */
872 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +0000873 struct pdp_t *pdp;
874 int n;
875 int starttime = time(NULL); /* Time program was started */
jjako7b8fad42003-07-07 14:37:42 +0000876 int stoptime = 0; /* Time to exit */
877 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +0000878
879 struct timezone tz; /* Used for calculating ping times */
880 struct timeval tv;
881 int diff;
jjako52c24142002-12-16 13:33:51 +0000882
jjako52c24142002-12-16 13:33:51 +0000883 /* open a connection to the syslog daemon */
884 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
885 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
886
jjakoa7cd2492003-04-11 09:40:12 +0000887 /* Process options given in configuration file and command line */
888 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +0000889 exit(1);
jjako52c24142002-12-16 13:33:51 +0000890
891 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +0000892 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +0000893 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
894 "Failed to create gtp");
895 exit(1);
896 }
jjako08d331d2003-10-13 20:33:30 +0000897 if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
898 if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
899 if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +0000900
jjakoa7cd2492003-04-11 09:40:12 +0000901 gtp_set_cb_delete_context(gsn, delete_context);
902 gtp_set_cb_conf(gsn, conf);
903 if (options.createif)
jjako08d331d2003-10-13 20:33:30 +0000904 gtp_set_cb_data_ind(gsn, encaps_tun);
jjako5da68452003-01-28 16:08:47 +0000905 else
jjako08d331d2003-10-13 20:33:30 +0000906 gtp_set_cb_data_ind(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +0000907
908 if (options.createif) {
909 printf("Setting up interface\n");
910 /* Create a tunnel interface */
911 if (tun_new((struct tun_t**) &tun)) {
912 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
913 "Failed to create tun");
914 exit(1);
915 }
916 tun_set_cb_ind(tun, cb_tun_ind);
917 if (tun->fd > maxfd) maxfd = tun->fd;
918 }
919
920 /* Initialise hash tables */
921 memset(&iphash, 0, sizeof(iphash));
922 memset(&iparr, 0, sizeof(iparr));
923
jjako52c24142002-12-16 13:33:51 +0000924 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +0000925
926 /* See if anybody is there */
927 printf("Sending off echo request\n");
jjako08d331d2003-10-13 20:33:30 +0000928 gtp_echo_req(gsn, 1, NULL, &options.remote); /* See if remote is alive ? */
929 gtp_echo_req(gsn, 0, NULL, &options.remote); /* See if remote is alive ? */
jjako52c24142002-12-16 13:33:51 +0000930
jjakoa7cd2492003-04-11 09:40:12 +0000931 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +0000932 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +0000933 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +0000934
jjakoa7cd2492003-04-11 09:40:12 +0000935 /* Allocated here. Cleaned up in gtp.c:*/
936 pdp_newpdp(&pdp, options.imsi, n, NULL);
937
938 pdp->peer = &iparr[n];
939 pdp->ipif = tun; /* TODO */
940 iparr[n].pdp = pdp;
941
942 if (options.qos.l > sizeof(pdp->qos_req0)) {
943 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +0000944 exit(1);
945 }
946 else {
jjakoa7cd2492003-04-11 09:40:12 +0000947 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000948 }
jjako08d331d2003-10-13 20:33:30 +0000949
950 /* TODO */
951 pdp->qos_req.l = 4;
952 pdp->qos_req.v[0] = 0x00;
953 memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000954
jjakoa7cd2492003-04-11 09:40:12 +0000955 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +0000956
jjakoa7cd2492003-04-11 09:40:12 +0000957 if (options.apn.l > sizeof(pdp->apn_use.v)) {
958 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +0000959 exit(1);
960 }
961 else {
jjakoa7cd2492003-04-11 09:40:12 +0000962 pdp->apn_use.l = options.apn.l;
963 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +0000964 }
965
jjakoa7cd2492003-04-11 09:40:12 +0000966 pdp->gsnlc.l = sizeof(options.listen);
967 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
968 pdp->gsnlu.l = sizeof(options.listen);
969 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +0000970
jjakoa7cd2492003-04-11 09:40:12 +0000971 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
972 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +0000973 exit(1);
974 }
975 else {
jjakoa7cd2492003-04-11 09:40:12 +0000976 pdp->msisdn.l = options.msisdn.l;
977 memcpy(pdp->msisdn.v, options.msisdn.v, options.msisdn.l);
978 }
979
980 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
981
982 if (options.pco.l > sizeof(pdp->pco_req.v)) {
983 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
984 exit(1);
985 }
986 else {
987 pdp->pco_req.l = options.pco.l;
988 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +0000989 }
990
jjako08d331d2003-10-13 20:33:30 +0000991 pdp->version = 1; /* First try with version 1 */
992
jjako52c24142002-12-16 13:33:51 +0000993 /* Create context */
994 /* We send this of once. Retransmissions are handled by gtplib */
jjako2c381332003-10-21 19:09:53 +0000995 gtp_create_context_req(gsn, pdp, &iparr[n], &options.remote);
jjako52c24142002-12-16 13:33:51 +0000996 }
997
998 state = 1; /* Enter wait_connection state */
999
1000 printf("Waiting for response from ggsn........\n\n");
1001
jjako5da68452003-01-28 16:08:47 +00001002
jjako52c24142002-12-16 13:33:51 +00001003 /******************************************************************/
1004 /* Main select loop */
1005 /******************************************************************/
1006
jjako7b8fad42003-07-07 14:37:42 +00001007 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001008
jjako7b8fad42003-07-07 14:37:42 +00001009 /* Take down client after timeout after disconnect */
1010 if ((4 == state) && ((stoptime) <= time(NULL))) {
1011 state = 5;
1012 }
1013
1014 /* Take down client after timelimit timeout */
1015 if ((2 == state) && (options.timelimit) &&
1016 ((starttime + options.timelimit) <= time(NULL))) {
jjako52c24142002-12-16 13:33:51 +00001017 state = 3;
jjako7b8fad42003-07-07 14:37:42 +00001018 }
1019
1020 /* Take down client after ping timeout */
1021 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
1022 state = 3;
1023 }
1024
1025 /* Set pingtimeout for later disconnection */
1026 if (options.pingcount && ntransmitted >= options.pingcount) {
1027 pingtimeout = time(NULL) + 5; /* Extra seconds */
1028 }
1029
1030 /* Print statistics if no more ping packets are missing */
1031 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1032 ping_finish();
1033 if (!options.createif)
1034 state = 3;
1035 }
1036
jjako2c381332003-10-21 19:09:53 +00001037 /* Send off disconnect */
jjako7b8fad42003-07-07 14:37:42 +00001038 if (3 == state) {
1039 state = 4;
1040 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
jjakoa7cd2492003-04-11 09:40:12 +00001041 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +00001042 /* Delete context */
1043 printf("Disconnecting PDP context #%d\n", n);
jjako2c381332003-10-21 19:09:53 +00001044 gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
jjakoa7cd2492003-04-11 09:40:12 +00001045 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +00001046 }
jjakoafb2a972003-01-29 21:04:13 +00001047 }
jjako7b8fad42003-07-07 14:37:42 +00001048
1049 /* Send of ping packets */
jjakoa7cd2492003-04-11 09:40:12 +00001050 diff = 0;
1051 while (( diff<=0 ) &&
jjako7b8fad42003-07-07 14:37:42 +00001052 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +00001053 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
jjako7b8fad42003-07-07 14:37:42 +00001054 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +00001055 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1056 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +00001057 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +00001058 1000000 * (tv.tv_sec - firstping.tv_sec) -
1059 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1060 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001061 if (options.debug) printf("Create_ping %d\n", diff);
1062 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1063 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001064 pingseq++;
1065 }
jjako52c24142002-12-16 13:33:51 +00001066 }
jjako5da68452003-01-28 16:08:47 +00001067
jjako52c24142002-12-16 13:33:51 +00001068 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001069 if (tun) FD_SET(tun->fd, &fds);
jjako08d331d2003-10-13 20:33:30 +00001070 FD_SET(gsn->fd0, &fds);
1071 FD_SET(gsn->fd1c, &fds);
1072 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +00001073
1074 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001075 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001076
1077 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1078 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1079
jjako52c24142002-12-16 13:33:51 +00001080 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1081 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001082 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1083 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001084 break;
1085 case 0:
1086 gtp_retrans(gsn); /* Only retransmit if nothing else */
1087 break;
1088 default:
1089 break;
1090 }
jjakoa7cd2492003-04-11 09:40:12 +00001091
1092 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1093 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1094 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001095 }
1096
jjako08d331d2003-10-13 20:33:30 +00001097 if (FD_ISSET(gsn->fd0, &fds))
1098 gtp_decaps0(gsn);
1099
1100 if (FD_ISSET(gsn->fd1c, &fds))
1101 gtp_decaps1c(gsn);
1102
1103 if (FD_ISSET(gsn->fd1u, &fds))
1104 gtp_decaps1u(gsn);
jjako5da68452003-01-28 16:08:47 +00001105 }
jjakoa7cd2492003-04-11 09:40:12 +00001106
jjako52c24142002-12-16 13:33:51 +00001107 gtp_free(gsn); /* Clean up the gsn instance */
1108
jjakoa7cd2492003-04-11 09:40:12 +00001109 if (options.createif)
1110 tun_free(tun);
jjako7b8fad42003-07-07 14:37:42 +00001111
1112 if (0 == state)
1113 exit(1); /* Indicate error */
jjako52c24142002-12-16 13:33:51 +00001114
jjakoa7cd2492003-04-11 09:40:12 +00001115 return 0;
jjako52c24142002-12-16 13:33:51 +00001116}
1117