blob: 9befbfb3cba619f22852118a92ab372cabac60b5 [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 */
jjako581c9f02003-10-22 11:28:20 +000081int state = 0;
jjako52c24142002-12-16 13:33:51 +000082
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() */
jjako91aaf222003-10-22 10:09:32 +000086int echoversion = 1; /* First try this version */
jjako52c24142002-12-16 13:33:51 +000087
jjakoa7cd2492003-04-11 09:40:12 +000088/* Struct with local versions of gengetopt options */
89struct {
90 int debug; /* Print debug messages */
91 int createif; /* Create local network interface */
92 char *ipup, *ipdown; /* Filename of scripts */
93 int defaultroute; /* Set up default route */
94 struct in_addr pinghost; /* Remote ping host */
95 int pingrate;
96 int pingsize;
97 int pingcount;
98 int pingquiet;
99 struct in_addr listen;
100 struct in_addr remote;
101 struct in_addr dns;
102 int contexts; /* Number of contexts to create */
103 int timelimit; /* Number of seconds to be connected */
104 char *statedir;
105 uint64_t imsi;
106 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 {
122 u_int8_t ipver; /* Type and header length*/
123 u_int8_t tos; /* Type of Service */
124 u_int16_t length; /* Total length */
125 u_int16_t fragid; /* Identifier */
126 u_int16_t offset; /* Flags and fragment offset */
127 u_int8_t ttl; /* Time to live */
128 u_int8_t protocol; /* Protocol */
129 u_int16_t ipcheck; /* Header checksum */
130 u_int32_t src; /* Source address */
131 u_int32_t dst; /* Destination */
132 u_int8_t type; /* Type and header length*/
133 u_int8_t code; /* Code */
134 u_int16_t checksum; /* Header checksum */
135 u_int16_t ident; /* Identifier */
136 u_int16_t seq; /* Sequence number */
137 u_int8_t data[CREATEPING_MAX]; /* Data */
138} __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;
205 fprintf(file, "%d\n", getpid());
206 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
392 printf("IMSI is: %s (%#08llx)\n",
393 args_info.imsi_arg, options.imsi);
394
395
396 /* qos */
397 options.qos.l = 3;
398 options.qos.v[2] = (args_info.qos_arg) & 0xff;
399 options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
400 options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
401
402 /* contexts */
403 if (args_info.contexts_arg > MAXCONTEXTS) {
404 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
405 return -1;
406 }
407 options.contexts = args_info.contexts_arg;
408
409 /* Timelimit */
410 options.timelimit = args_info.timelimit_arg;
411
412 /* apn */
413 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
414 printf("Invalid APN\n");
415 return -1;
416 }
417 options.apn.l = strlen(args_info.apn_arg) + 1;
418 options.apn.v[0] = (char) strlen(args_info.apn_arg);
419 strncpy(&options.apn.v[1], args_info.apn_arg, sizeof(options.apn.v)-1);
420 printf("Using APN: %s\n", args_info.apn_arg);
421
422 /* msisdn */
423 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
424 printf("Invalid MSISDN\n");
425 return -1;
426 }
427 options.msisdn.l = 1;
428 options.msisdn.v[0] = 0x91; /* International format */
429 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
430 if ((n%2) == 0) {
431 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
432 options.msisdn.l += 1;
433 }
434 else {
435 options.msisdn.v[((int)n/2)+1] =
436 (options.msisdn.v[((int)n/2)+1] & 0x0f) +
437 (args_info.msisdn_arg[n] - 48) * 16;
438 }
439 }
440 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
441
442 /* UID and PWD */
443 /* Might need to also insert stuff like DNS etc. */
444 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>
445 (sizeof(options.pco.v)-1)) {
446 printf("invalid UID and PWD\n");
447 return -1;
448 }
449 options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
450 options.pco.v[0] = 0x80; /* PPP */
451 options.pco.v[1] = 0xc0; /* PAP */
452 options.pco.v[2] = 0x23;
453 options.pco.v[3] = 0x12; /* Length of protocol contents */
454 options.pco.v[4] = 0x01; /* Authenticate request */
455 options.pco.v[5] = 0x01;
456 options.pco.v[6] = 0x00; /* MSB of length */
457 options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
458 options.pco.v[8] = strlen(args_info.uid_arg);
459 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
460 options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg);
461 memcpy(&options.pco.v[10+strlen(args_info.uid_arg)],
462 args_info.pwd_arg, strlen(args_info.pwd_arg));
463
464 /* createif */
465 options.createif = args_info.createif_flag;
466
467 /* ipup */
468 options.ipup = args_info.ipup_arg;
469
470 /* ipdown */
471 options.ipdown = args_info.ipdown_arg;
472
473 /* statedir */
474 options.statedir = args_info.statedir_arg;
475
476 /* defaultroute */
477 options.defaultroute = args_info.defaultroute_flag;
478
479
480 /* pinghost */
481 /* Store ping host as in_addr */
482 if (args_info.pinghost_arg) {
483 if (!inet_aton(args_info.pinghost_arg, &options.pinghost)) {
484 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
485 "Invalid ping host: %s!", args_info.pinghost_arg);
486 return -1;
487 }
488 }
489
490 /* Other ping parameters */
491 options.pingrate = args_info.pingrate_arg;
492 options.pingsize = args_info.pingsize_arg;
493 options.pingcount = args_info.pingcount_arg;
494 options.pingquiet = args_info.pingquiet_flag;
495
496 return 0;
497
498}
499
jjako5da68452003-01-28 16:08:47 +0000500
501int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000502 int i;
503 printf("The packet looks like this:\n");
504 for( i=0; i<len; i++) {
jjako5da68452003-01-28 16:08:47 +0000505 printf("%02x ", (unsigned char)*(char *)(pack+i));
jjako52c24142002-12-16 13:33:51 +0000506 if (!((i+1)%16)) printf("\n");
507 };
jjako5da68452003-01-28 16:08:47 +0000508 printf("\n");
509 return 0;
jjako52c24142002-12-16 13:33:51 +0000510}
511
jjako5da68452003-01-28 16:08:47 +0000512char * print_ipprot(int t) {
513 switch (t) {
514 case 1: return "ICMP";
515 case 6: return "TCP";
516 case 17: return "UDP";
517 default: return "Unknown";
518 };
519}
520
521
522char * print_icmptype(int t) {
523 static char *ttab[] = {
524 "Echo Reply",
525 "ICMP 1",
526 "ICMP 2",
527 "Dest Unreachable",
528 "Source Quench",
529 "Redirect",
530 "ICMP 6",
531 "ICMP 7",
532 "Echo",
533 "ICMP 9",
534 "ICMP 10",
535 "Time Exceeded",
536 "Parameter Problem",
537 "Timestamp",
538 "Timestamp Reply",
539 "Info Request",
540 "Info Reply"
541 };
542 if( t < 0 || t > 16 )
543 return("OUT-OF-RANGE");
544 return(ttab[t]);
545}
546
jjakoafb2a972003-01-29 21:04:13 +0000547/* Calculate time left until we have to send off next ping packet */
548int ping_timeout(struct timeval *tp) {
549 struct timezone tz;
550 struct timeval tv;
551 int diff;
jjakoa7cd2492003-04-11 09:40:12 +0000552 if ((options.pinghost.s_addr) && (2 == state) &&
553 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000554 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000555 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000556 1000000 * (tv.tv_sec - firstping.tv_sec) -
557 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
558 tp->tv_sec = 0;
559 if (diff > 0)
560 tp->tv_usec = diff;
jjakoa7cd2492003-04-11 09:40:12 +0000561 else {
jjakoafb2a972003-01-29 21:04:13 +0000562 /* For some reason we get packet loss if set to zero */
jjakoa7cd2492003-04-11 09:40:12 +0000563 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
564 tp->tv_usec = 0;
565 }
jjakoafb2a972003-01-29 21:04:13 +0000566 }
567 return 0;
568}
569
jjako5da68452003-01-28 16:08:47 +0000570/* Print out statistics when at the end of ping sequence */
571int ping_finish()
572{
jjakoafb2a972003-01-29 21:04:13 +0000573 struct timezone tz;
574 struct timeval tv;
575 int elapsed;
576 gettimeofday(&tv, &tz);
577 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
578 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
jjako5da68452003-01-28 16:08:47 +0000579 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000580 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
jjakoafb2a972003-01-29 21:04:13 +0000581 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
582 elapsed / 1000000.0);
jjako5da68452003-01-28 16:08:47 +0000583 printf("%d packets received, ", nreceived );
584 if (ntransmitted) {
585 if( nreceived > ntransmitted)
586 printf("-- somebody's printing up packets!");
587 else
588 printf("%d%% packet loss",
589 (int) (((ntransmitted-nreceived)*100) /
590 ntransmitted));
591 }
592 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000593 if (options.debug) printf("%d packets received in total\n", ntreceived );
jjako5da68452003-01-28 16:08:47 +0000594 if (nreceived && tsum)
595 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
596 tmin/1000.0,
597 tsum/1000.0/nreceived,
598 tmax/1000.0 );
jjakoafb2a972003-01-29 21:04:13 +0000599 printf("%d packets transmitted \n", ntreceived );
600
jjako5da68452003-01-28 16:08:47 +0000601 ntransmitted = 0;
602 return 0;
603}
604
605/* Handle a received ping packet. Print out line and update statistics. */
606int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
607 struct timezone tz;
608 struct timeval tv;
609 struct timeval *tp;
610 struct ip_ping *pingpack = pack;
611 struct in_addr src;
612 int triptime;
613
614 src.s_addr = pingpack->src;
615
616 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000617 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +0000618
619 if (len < CREATEPING_IP + CREATEPING_ICMP) {
620 printf("packet too short (%d bytes) from %s\n", len,
621 inet_ntoa(src));
622 return 0;
623 }
624
625 ntreceived++;
626 if (pingpack->protocol != 1) {
jjakoa7cd2492003-04-11 09:40:12 +0000627 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
jjako5da68452003-01-28 16:08:47 +0000628 len, inet_ntoa(src), pingpack->protocol,
629 print_ipprot(pingpack->protocol));
630 return 0;
631 }
632
633 if (pingpack->type != 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000634 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
jjako5da68452003-01-28 16:08:47 +0000635 len, inet_ntoa(src), pingpack->type,
636 print_icmptype(pingpack->type), pingpack->code);
637 return 0;
638 }
639
640 nreceived++;
jjakoa7cd2492003-04-11 09:40:12 +0000641 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
jjako5da68452003-01-28 16:08:47 +0000642 inet_ntoa(src), ntohs(pingpack->seq));
643
644 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
645 gettimeofday(&tv, &tz);
646 tp = (struct timeval *) pingpack->data;
647 if( (tv.tv_usec -= tp->tv_usec) < 0 ) {
648 tv.tv_sec--;
649 tv.tv_usec += 1000000;
650 }
651 tv.tv_sec -= tp->tv_sec;
652
653 triptime = tv.tv_sec*1000000+(tv.tv_usec);
654 tsum += triptime;
655 if( triptime < tmin )
656 tmin = triptime;
657 if( triptime > tmax )
658 tmax = triptime;
659
jjakoa7cd2492003-04-11 09:40:12 +0000660 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
jjako5da68452003-01-28 16:08:47 +0000661
662 }
663 else
jjakoa7cd2492003-04-11 09:40:12 +0000664 if (!options.pingquiet) printf("\n");
jjako5da68452003-01-28 16:08:47 +0000665 return 0;
666}
667
668/* Create a new ping packet and send it off to peer. */
669int create_ping(void *gsn, struct pdp_t *pdp,
670 struct in_addr *dst, int seq, int datasize) {
671
672 struct ip_ping pack;
673 u_int16_t *p = (u_int16_t *) &pack;
674 u_int8_t *p8 = (u_int8_t *) &pack;
675 struct in_addr src;
676 int n;
677 long int sum = 0;
678 int count = 0;
679
680 struct timezone tz;
681 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
682
683 if (datasize > CREATEPING_MAX) {
jjakoa7cd2492003-04-11 09:40:12 +0000684 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
685 "Ping size to large: %d!", datasize);
686 return -1;
jjako5da68452003-01-28 16:08:47 +0000687 }
688
689 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
690
691 pack.ipver = 0x45;
692 pack.tos = 0x00;
693 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
694 pack.fragid = 0x0000;
695 pack.offset = 0x0040;
696 pack.ttl = 0x40;
697 pack.protocol = 0x01;
698 pack.ipcheck = 0x0000;
699 pack.src = src.s_addr;
700 pack.dst = dst->s_addr;
701 pack.type = 0x08;
702 pack.code = 0x00;
703 pack.checksum = 0x0000;
704 pack.ident = 0x0000;
705 pack.seq = htons(seq);
706
707 /* Generate ICMP payload */
708 p8 = (u_int8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
709 for (n=0; n<(datasize); n++) p8[n] = n;
710
711 if (datasize >= sizeof(struct timeval))
712 gettimeofday(tp, &tz);
713
714 /* Calculate IP header checksum */
715 p = (u_int16_t *) &pack;
716 count = CREATEPING_IP;
717 sum = 0;
718 while (count>1) {
719 sum += *p++;
720 count -= 2;
721 }
722 while (sum>>16)
723 sum = (sum & 0xffff) + (sum >> 16);
724 pack.ipcheck = ~sum;
725
726
727 /* Calculate ICMP checksum */
728 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
729 sum = 0;
730 p = (u_int16_t *) &pack;
731 p += CREATEPING_IP / 2;
732 while (count>1) {
733 sum += *p++;
734 count -= 2;
735 }
736 if (count>0)
737 sum += * (unsigned char *) p;
738 while (sum>>16)
739 sum = (sum & 0xffff) + (sum >> 16);
740 pack.checksum = ~sum;
741
742 ntransmitted++;
jjako08d331d2003-10-13 20:33:30 +0000743 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
jjako5da68452003-01-28 16:08:47 +0000744}
745
746
jjakoa7cd2492003-04-11 09:40:12 +0000747int delete_context(struct pdp_t *pdp) {
748
749 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
750
751 ipdel((struct iphash_t*) pdp->peer);
752 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
jjako7b8fad42003-07-07 14:37:42 +0000753
754 if (1 == options.contexts)
755 state = 5; /* Disconnected */
756
jjakoa7cd2492003-04-11 09:40:12 +0000757 return 0;
jjako52c24142002-12-16 13:33:51 +0000758}
759
jjakoa7cd2492003-04-11 09:40:12 +0000760
761/* Callback for receiving messages from tun */
762int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
763 struct iphash_t *ipm;
764 struct in_addr src;
765 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
766
767 src.s_addr = iph->src;
768
769 if (ipget(&ipm, &src)) {
770 printf("Received packet without a valid source address!!!\n");
771 return 0;
jjako52c24142002-12-16 13:33:51 +0000772 }
jjako5da68452003-01-28 16:08:47 +0000773
jjakoa7cd2492003-04-11 09:40:12 +0000774 if (ipm->pdp) /* Check if a peer protocol is defined */
jjako08d331d2003-10-13 20:33:30 +0000775 gtp_data_req(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000776 return 0;
777}
778
jjako2c381332003-10-21 19:09:53 +0000779int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000780 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000781
jjako2c381332003-10-21 19:09:53 +0000782 struct iphash_t *iph = (struct iphash_t*) cbp;
783
784 if (cause < 0) {
785 printf("Create PDP Context Request timed out\n");
786 if (iph->pdp->version == 1) {
787 printf("Retrying with version 0\n");
788 iph->pdp->version = 0;
789 gtp_create_context_req(gsn, iph->pdp, iph, &options.remote);
jjako2c381332003-10-21 19:09:53 +0000790 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) {
jjako91aaf222003-10-22 10:09:32 +0000839
840 if (recovery < 0) {
841 printf("Echo Request timed out\n");
842 if (echoversion == 1) {
843 printf("Retrying with version 0\n");
844 echoversion = 0;
845 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
jjako91aaf222003-10-22 10:09:32 +0000846 return 0;
847 }
848 else {
849 state = 0;
850 return EOF;
851 }
jjako7b8fad42003-07-07 14:37:42 +0000852 }
jjako581c9f02003-10-22 11:28:20 +0000853 else {
jjako08d331d2003-10-13 20:33:30 +0000854 printf("Received echo response\n");
jjako581c9f02003-10-22 11:28:20 +0000855 if (!options.contexts) state = 5;
856 }
jjako52c24142002-12-16 13:33:51 +0000857 return 0;
858}
859
jjako2c381332003-10-21 19:09:53 +0000860int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000861 /* if (cause < 0) return 0; Some error occurred. We don't care */
862 switch (type) {
863 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +0000864 return echo_conf(cause);
jjako52c24142002-12-16 13:33:51 +0000865 case GTP_CREATE_PDP_REQ:
jjako2c381332003-10-21 19:09:53 +0000866 return create_pdp_conf(pdp, cbp, cause);
jjako52c24142002-12-16 13:33:51 +0000867 case GTP_DELETE_PDP_REQ:
868 if (cause !=128) return 0; /* Request not accepted. We don't care */
869 return delete_pdp_conf(pdp, cause);
870 default:
871 return 0;
872 }
873}
874
jjako52c24142002-12-16 13:33:51 +0000875
876int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
877 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
878 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
879}
880
881int main(int argc, char **argv)
882{
jjako52c24142002-12-16 13:33:51 +0000883 fd_set fds; /* For select() */
884 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +0000885 struct pdp_t *pdp;
886 int n;
887 int starttime = time(NULL); /* Time program was started */
jjako7b8fad42003-07-07 14:37:42 +0000888 int stoptime = 0; /* Time to exit */
889 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +0000890
891 struct timezone tz; /* Used for calculating ping times */
892 struct timeval tv;
893 int diff;
jjako52c24142002-12-16 13:33:51 +0000894
jjako52c24142002-12-16 13:33:51 +0000895 /* open a connection to the syslog daemon */
896 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
897 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
898
jjakoa7cd2492003-04-11 09:40:12 +0000899 /* Process options given in configuration file and command line */
900 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +0000901 exit(1);
jjako52c24142002-12-16 13:33:51 +0000902
903 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +0000904 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +0000905 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
906 "Failed to create gtp");
907 exit(1);
908 }
jjako08d331d2003-10-13 20:33:30 +0000909 if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
910 if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
911 if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +0000912
jjakoa7cd2492003-04-11 09:40:12 +0000913 gtp_set_cb_delete_context(gsn, delete_context);
914 gtp_set_cb_conf(gsn, conf);
915 if (options.createif)
jjako08d331d2003-10-13 20:33:30 +0000916 gtp_set_cb_data_ind(gsn, encaps_tun);
jjako5da68452003-01-28 16:08:47 +0000917 else
jjako08d331d2003-10-13 20:33:30 +0000918 gtp_set_cb_data_ind(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +0000919
920 if (options.createif) {
921 printf("Setting up interface\n");
922 /* Create a tunnel interface */
923 if (tun_new((struct tun_t**) &tun)) {
924 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
925 "Failed to create tun");
926 exit(1);
927 }
928 tun_set_cb_ind(tun, cb_tun_ind);
929 if (tun->fd > maxfd) maxfd = tun->fd;
930 }
931
932 /* Initialise hash tables */
933 memset(&iphash, 0, sizeof(iphash));
934 memset(&iparr, 0, sizeof(iparr));
935
jjako52c24142002-12-16 13:33:51 +0000936 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +0000937
938 /* See if anybody is there */
939 printf("Sending off echo request\n");
jjako91aaf222003-10-22 10:09:32 +0000940 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjako52c24142002-12-16 13:33:51 +0000941
jjakoa7cd2492003-04-11 09:40:12 +0000942 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +0000943 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +0000944 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +0000945
jjakoa7cd2492003-04-11 09:40:12 +0000946 /* Allocated here. Cleaned up in gtp.c:*/
947 pdp_newpdp(&pdp, options.imsi, n, NULL);
948
949 pdp->peer = &iparr[n];
950 pdp->ipif = tun; /* TODO */
951 iparr[n].pdp = pdp;
952
953 if (options.qos.l > sizeof(pdp->qos_req0)) {
954 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +0000955 exit(1);
956 }
957 else {
jjakoa7cd2492003-04-11 09:40:12 +0000958 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000959 }
jjako08d331d2003-10-13 20:33:30 +0000960
961 /* TODO */
962 pdp->qos_req.l = 4;
963 pdp->qos_req.v[0] = 0x00;
964 memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000965
jjakoa7cd2492003-04-11 09:40:12 +0000966 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +0000967
jjakoa7cd2492003-04-11 09:40:12 +0000968 if (options.apn.l > sizeof(pdp->apn_use.v)) {
969 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +0000970 exit(1);
971 }
972 else {
jjakoa7cd2492003-04-11 09:40:12 +0000973 pdp->apn_use.l = options.apn.l;
974 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +0000975 }
976
jjakoa7cd2492003-04-11 09:40:12 +0000977 pdp->gsnlc.l = sizeof(options.listen);
978 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
979 pdp->gsnlu.l = sizeof(options.listen);
980 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +0000981
jjakoa7cd2492003-04-11 09:40:12 +0000982 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
983 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +0000984 exit(1);
985 }
986 else {
jjakoa7cd2492003-04-11 09:40:12 +0000987 pdp->msisdn.l = options.msisdn.l;
988 memcpy(pdp->msisdn.v, options.msisdn.v, options.msisdn.l);
989 }
990
991 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
992
993 if (options.pco.l > sizeof(pdp->pco_req.v)) {
994 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
995 exit(1);
996 }
997 else {
998 pdp->pco_req.l = options.pco.l;
999 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +00001000 }
1001
jjako08d331d2003-10-13 20:33:30 +00001002 pdp->version = 1; /* First try with version 1 */
1003
jjako52c24142002-12-16 13:33:51 +00001004 /* Create context */
1005 /* We send this of once. Retransmissions are handled by gtplib */
jjako2c381332003-10-21 19:09:53 +00001006 gtp_create_context_req(gsn, pdp, &iparr[n], &options.remote);
jjako52c24142002-12-16 13:33:51 +00001007 }
1008
1009 state = 1; /* Enter wait_connection state */
1010
1011 printf("Waiting for response from ggsn........\n\n");
1012
jjako5da68452003-01-28 16:08:47 +00001013
jjako52c24142002-12-16 13:33:51 +00001014 /******************************************************************/
1015 /* Main select loop */
1016 /******************************************************************/
1017
jjako7b8fad42003-07-07 14:37:42 +00001018 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001019
jjako7b8fad42003-07-07 14:37:42 +00001020 /* Take down client after timeout after disconnect */
1021 if ((4 == state) && ((stoptime) <= time(NULL))) {
1022 state = 5;
1023 }
1024
1025 /* Take down client after timelimit timeout */
1026 if ((2 == state) && (options.timelimit) &&
1027 ((starttime + options.timelimit) <= time(NULL))) {
jjako52c24142002-12-16 13:33:51 +00001028 state = 3;
jjako7b8fad42003-07-07 14:37:42 +00001029 }
1030
1031 /* Take down client after ping timeout */
1032 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
1033 state = 3;
1034 }
1035
1036 /* Set pingtimeout for later disconnection */
1037 if (options.pingcount && ntransmitted >= options.pingcount) {
1038 pingtimeout = time(NULL) + 5; /* Extra seconds */
1039 }
1040
1041 /* Print statistics if no more ping packets are missing */
1042 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1043 ping_finish();
1044 if (!options.createif)
1045 state = 3;
1046 }
1047
jjako2c381332003-10-21 19:09:53 +00001048 /* Send off disconnect */
jjako7b8fad42003-07-07 14:37:42 +00001049 if (3 == state) {
1050 state = 4;
1051 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
jjakoa7cd2492003-04-11 09:40:12 +00001052 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +00001053 /* Delete context */
1054 printf("Disconnecting PDP context #%d\n", n);
jjako2c381332003-10-21 19:09:53 +00001055 gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
jjakoa7cd2492003-04-11 09:40:12 +00001056 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +00001057 }
jjakoafb2a972003-01-29 21:04:13 +00001058 }
jjako7b8fad42003-07-07 14:37:42 +00001059
1060 /* Send of ping packets */
jjakoa7cd2492003-04-11 09:40:12 +00001061 diff = 0;
1062 while (( diff<=0 ) &&
jjako7b8fad42003-07-07 14:37:42 +00001063 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +00001064 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
jjako7b8fad42003-07-07 14:37:42 +00001065 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +00001066 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1067 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +00001068 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +00001069 1000000 * (tv.tv_sec - firstping.tv_sec) -
1070 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1071 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001072 if (options.debug) printf("Create_ping %d\n", diff);
1073 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1074 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001075 pingseq++;
1076 }
jjako52c24142002-12-16 13:33:51 +00001077 }
jjako5da68452003-01-28 16:08:47 +00001078
jjako52c24142002-12-16 13:33:51 +00001079 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001080 if (tun) FD_SET(tun->fd, &fds);
jjako08d331d2003-10-13 20:33:30 +00001081 FD_SET(gsn->fd0, &fds);
1082 FD_SET(gsn->fd1c, &fds);
1083 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +00001084
1085 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001086 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001087
1088 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1089 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1090
jjako52c24142002-12-16 13:33:51 +00001091 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1092 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001093 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1094 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001095 break;
1096 case 0:
1097 gtp_retrans(gsn); /* Only retransmit if nothing else */
1098 break;
1099 default:
1100 break;
1101 }
jjakoa7cd2492003-04-11 09:40:12 +00001102
1103 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1104 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1105 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001106 }
1107
jjako08d331d2003-10-13 20:33:30 +00001108 if (FD_ISSET(gsn->fd0, &fds))
1109 gtp_decaps0(gsn);
1110
1111 if (FD_ISSET(gsn->fd1c, &fds))
1112 gtp_decaps1c(gsn);
1113
1114 if (FD_ISSET(gsn->fd1u, &fds))
1115 gtp_decaps1u(gsn);
jjako5da68452003-01-28 16:08:47 +00001116 }
jjakoa7cd2492003-04-11 09:40:12 +00001117
jjako52c24142002-12-16 13:33:51 +00001118 gtp_free(gsn); /* Clean up the gsn instance */
1119
jjakoa7cd2492003-04-11 09:40:12 +00001120 if (options.createif)
1121 tun_free(tun);
jjako7b8fad42003-07-07 14:37:42 +00001122
1123 if (0 == state)
1124 exit(1); /* Indicate error */
jjako52c24142002-12-16 13:33:51 +00001125
jjakoa7cd2492003-04-11 09:40:12 +00001126 return 0;
jjako52c24142002-12-16 13:33:51 +00001127}
1128