blob: e636f1b0ea889fa8b5cd5c08f2e8fa363ed2d88f [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;
jjako0b076a32003-10-25 15:59:31 +0000794 pdp_freepdp(iph->pdp);
795 iph->pdp = NULL;
jjako2c381332003-10-21 19:09:53 +0000796 return EOF;
797 }
798 }
799
jjakoa7cd2492003-04-11 09:40:12 +0000800 if (cause != 128) {
801 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000802 state = 0;
jjako0b076a32003-10-25 15:59:31 +0000803 pdp_freepdp(iph->pdp);
804 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000805 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000806 }
807
jjakoa7cd2492003-04-11 09:40:12 +0000808 if (pdp_euaton(&pdp->eua, &addr)) {
809 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako0b076a32003-10-25 15:59:31 +0000810 pdp_freepdp(iph->pdp);
811 iph->pdp = NULL;
jjakoa7cd2492003-04-11 09:40:12 +0000812 state = 0;
813 return EOF; /* Not a valid IP address */
814 }
815
816 printf("Received create PDP context response. IP address: %s\n",
817 inet_ntoa(addr));
818
819 if (options.createif) {
820 struct in_addr m;
821 inet_aton("255.255.255.255", &m);
822 /* printf("Setting up interface and routing\n");*/
823 tun_addaddr(tun, &addr, &addr, &m);
824 if (options.defaultroute) {
825 struct in_addr rm;
826 rm.s_addr = 0;
827 tun_addroute(tun, &rm, &addr, &rm);
828 }
829 if (options.ipup) tun_runscript(tun, options.ipup);
830 }
831
832 ipset((struct iphash_t*) pdp->peer, &addr);
833
834 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000835
836 return 0;
837}
838
jjako52c24142002-12-16 13:33:51 +0000839int delete_pdp_conf(struct pdp_t *pdp, int cause) {
840 printf("Received delete PDP context response. Cause value: %d\n", cause);
841 return 0;
842}
843
jjako08d331d2003-10-13 20:33:30 +0000844int echo_conf(int recovery) {
jjako91aaf222003-10-22 10:09:32 +0000845
846 if (recovery < 0) {
847 printf("Echo Request timed out\n");
848 if (echoversion == 1) {
849 printf("Retrying with version 0\n");
850 echoversion = 0;
851 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
jjako91aaf222003-10-22 10:09:32 +0000852 return 0;
853 }
854 else {
855 state = 0;
856 return EOF;
857 }
jjako7b8fad42003-07-07 14:37:42 +0000858 }
jjako581c9f02003-10-22 11:28:20 +0000859 else {
jjako08d331d2003-10-13 20:33:30 +0000860 printf("Received echo response\n");
jjako581c9f02003-10-22 11:28:20 +0000861 if (!options.contexts) state = 5;
862 }
jjako52c24142002-12-16 13:33:51 +0000863 return 0;
864}
865
jjako2c381332003-10-21 19:09:53 +0000866int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
jjako52c24142002-12-16 13:33:51 +0000867 /* if (cause < 0) return 0; Some error occurred. We don't care */
868 switch (type) {
869 case GTP_ECHO_REQ:
jjako08d331d2003-10-13 20:33:30 +0000870 return echo_conf(cause);
jjako52c24142002-12-16 13:33:51 +0000871 case GTP_CREATE_PDP_REQ:
jjako2c381332003-10-21 19:09:53 +0000872 return create_pdp_conf(pdp, cbp, cause);
jjako52c24142002-12-16 13:33:51 +0000873 case GTP_DELETE_PDP_REQ:
874 if (cause !=128) return 0; /* Request not accepted. We don't care */
875 return delete_pdp_conf(pdp, cause);
876 default:
877 return 0;
878 }
879}
880
jjako52c24142002-12-16 13:33:51 +0000881
882int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
883 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
884 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
885}
886
887int main(int argc, char **argv)
888{
jjako52c24142002-12-16 13:33:51 +0000889 fd_set fds; /* For select() */
890 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +0000891 struct pdp_t *pdp;
892 int n;
893 int starttime = time(NULL); /* Time program was started */
jjako7b8fad42003-07-07 14:37:42 +0000894 int stoptime = 0; /* Time to exit */
895 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +0000896
897 struct timezone tz; /* Used for calculating ping times */
898 struct timeval tv;
899 int diff;
jjako52c24142002-12-16 13:33:51 +0000900
jjako52c24142002-12-16 13:33:51 +0000901 /* open a connection to the syslog daemon */
902 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
903 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
904
jjakoa7cd2492003-04-11 09:40:12 +0000905 /* Process options given in configuration file and command line */
906 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +0000907 exit(1);
jjako52c24142002-12-16 13:33:51 +0000908
909 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +0000910 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +0000911 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
912 "Failed to create gtp");
913 exit(1);
914 }
jjako08d331d2003-10-13 20:33:30 +0000915 if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
916 if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
917 if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;
jjako52c24142002-12-16 13:33:51 +0000918
jjakoa7cd2492003-04-11 09:40:12 +0000919 gtp_set_cb_delete_context(gsn, delete_context);
920 gtp_set_cb_conf(gsn, conf);
921 if (options.createif)
jjako08d331d2003-10-13 20:33:30 +0000922 gtp_set_cb_data_ind(gsn, encaps_tun);
jjako5da68452003-01-28 16:08:47 +0000923 else
jjako08d331d2003-10-13 20:33:30 +0000924 gtp_set_cb_data_ind(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +0000925
926 if (options.createif) {
927 printf("Setting up interface\n");
928 /* Create a tunnel interface */
929 if (tun_new((struct tun_t**) &tun)) {
930 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
931 "Failed to create tun");
932 exit(1);
933 }
934 tun_set_cb_ind(tun, cb_tun_ind);
935 if (tun->fd > maxfd) maxfd = tun->fd;
936 }
937
938 /* Initialise hash tables */
939 memset(&iphash, 0, sizeof(iphash));
940 memset(&iparr, 0, sizeof(iparr));
941
jjako52c24142002-12-16 13:33:51 +0000942 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +0000943
944 /* See if anybody is there */
945 printf("Sending off echo request\n");
jjako91aaf222003-10-22 10:09:32 +0000946 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
jjako52c24142002-12-16 13:33:51 +0000947
jjakoa7cd2492003-04-11 09:40:12 +0000948 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +0000949 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +0000950 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +0000951
jjako0b076a32003-10-25 15:59:31 +0000952 /* Allocated here. */
953 /* If create context failes we have to deallocate ourselves. */
954 /* Otherwise it is deallocated gy gtplib */
jjakoa7cd2492003-04-11 09:40:12 +0000955 pdp_newpdp(&pdp, options.imsi, n, NULL);
956
957 pdp->peer = &iparr[n];
958 pdp->ipif = tun; /* TODO */
959 iparr[n].pdp = pdp;
960
961 if (options.qos.l > sizeof(pdp->qos_req0)) {
962 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +0000963 exit(1);
964 }
965 else {
jjakoa7cd2492003-04-11 09:40:12 +0000966 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000967 }
jjako08d331d2003-10-13 20:33:30 +0000968
969 /* TODO */
970 pdp->qos_req.l = 4;
971 pdp->qos_req.v[0] = 0x00;
972 memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000973
jjakoa7cd2492003-04-11 09:40:12 +0000974 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +0000975
jjakoa7cd2492003-04-11 09:40:12 +0000976 if (options.apn.l > sizeof(pdp->apn_use.v)) {
977 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +0000978 exit(1);
979 }
980 else {
jjakoa7cd2492003-04-11 09:40:12 +0000981 pdp->apn_use.l = options.apn.l;
982 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +0000983 }
984
jjakoa7cd2492003-04-11 09:40:12 +0000985 pdp->gsnlc.l = sizeof(options.listen);
986 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
987 pdp->gsnlu.l = sizeof(options.listen);
988 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +0000989
jjakoa7cd2492003-04-11 09:40:12 +0000990 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
991 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +0000992 exit(1);
993 }
994 else {
jjakoa7cd2492003-04-11 09:40:12 +0000995 pdp->msisdn.l = options.msisdn.l;
996 memcpy(pdp->msisdn.v, options.msisdn.v, options.msisdn.l);
997 }
998
999 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
1000
1001 if (options.pco.l > sizeof(pdp->pco_req.v)) {
1002 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
1003 exit(1);
1004 }
1005 else {
1006 pdp->pco_req.l = options.pco.l;
1007 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +00001008 }
1009
jjako08d331d2003-10-13 20:33:30 +00001010 pdp->version = 1; /* First try with version 1 */
1011
jjako52c24142002-12-16 13:33:51 +00001012 /* Create context */
1013 /* We send this of once. Retransmissions are handled by gtplib */
jjako2c381332003-10-21 19:09:53 +00001014 gtp_create_context_req(gsn, pdp, &iparr[n], &options.remote);
jjako52c24142002-12-16 13:33:51 +00001015 }
1016
1017 state = 1; /* Enter wait_connection state */
1018
1019 printf("Waiting for response from ggsn........\n\n");
1020
jjako5da68452003-01-28 16:08:47 +00001021
jjako52c24142002-12-16 13:33:51 +00001022 /******************************************************************/
1023 /* Main select loop */
1024 /******************************************************************/
1025
jjako7b8fad42003-07-07 14:37:42 +00001026 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +00001027
jjako7b8fad42003-07-07 14:37:42 +00001028 /* Take down client after timeout after disconnect */
1029 if ((4 == state) && ((stoptime) <= time(NULL))) {
1030 state = 5;
1031 }
1032
1033 /* Take down client after timelimit timeout */
1034 if ((2 == state) && (options.timelimit) &&
1035 ((starttime + options.timelimit) <= time(NULL))) {
jjako52c24142002-12-16 13:33:51 +00001036 state = 3;
jjako7b8fad42003-07-07 14:37:42 +00001037 }
1038
1039 /* Take down client after ping timeout */
1040 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
1041 state = 3;
1042 }
1043
1044 /* Set pingtimeout for later disconnection */
1045 if (options.pingcount && ntransmitted >= options.pingcount) {
1046 pingtimeout = time(NULL) + 5; /* Extra seconds */
1047 }
1048
1049 /* Print statistics if no more ping packets are missing */
1050 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1051 ping_finish();
1052 if (!options.createif)
1053 state = 3;
1054 }
1055
jjako2c381332003-10-21 19:09:53 +00001056 /* Send off disconnect */
jjako7b8fad42003-07-07 14:37:42 +00001057 if (3 == state) {
1058 state = 4;
1059 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
jjakoa7cd2492003-04-11 09:40:12 +00001060 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +00001061 /* Delete context */
1062 printf("Disconnecting PDP context #%d\n", n);
jjako2c381332003-10-21 19:09:53 +00001063 gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
jjakoa7cd2492003-04-11 09:40:12 +00001064 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +00001065 }
jjakoafb2a972003-01-29 21:04:13 +00001066 }
jjako7b8fad42003-07-07 14:37:42 +00001067
1068 /* Send of ping packets */
jjakoa7cd2492003-04-11 09:40:12 +00001069 diff = 0;
1070 while (( diff<=0 ) &&
jjako7b8fad42003-07-07 14:37:42 +00001071 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +00001072 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
jjako7b8fad42003-07-07 14:37:42 +00001073 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +00001074 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1075 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +00001076 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +00001077 1000000 * (tv.tv_sec - firstping.tv_sec) -
1078 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1079 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001080 if (options.debug) printf("Create_ping %d\n", diff);
1081 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1082 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001083 pingseq++;
1084 }
jjako52c24142002-12-16 13:33:51 +00001085 }
jjako5da68452003-01-28 16:08:47 +00001086
jjako52c24142002-12-16 13:33:51 +00001087 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001088 if (tun) FD_SET(tun->fd, &fds);
jjako08d331d2003-10-13 20:33:30 +00001089 FD_SET(gsn->fd0, &fds);
1090 FD_SET(gsn->fd1c, &fds);
1091 FD_SET(gsn->fd1u, &fds);
jjako52c24142002-12-16 13:33:51 +00001092
1093 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001094 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001095
1096 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1097 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1098
jjako52c24142002-12-16 13:33:51 +00001099 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1100 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001101 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1102 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001103 break;
1104 case 0:
1105 gtp_retrans(gsn); /* Only retransmit if nothing else */
1106 break;
1107 default:
1108 break;
1109 }
jjakoa7cd2492003-04-11 09:40:12 +00001110
1111 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1112 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1113 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001114 }
1115
jjako08d331d2003-10-13 20:33:30 +00001116 if (FD_ISSET(gsn->fd0, &fds))
1117 gtp_decaps0(gsn);
1118
1119 if (FD_ISSET(gsn->fd1c, &fds))
1120 gtp_decaps1c(gsn);
1121
1122 if (FD_ISSET(gsn->fd1u, &fds))
1123 gtp_decaps1u(gsn);
jjako5da68452003-01-28 16:08:47 +00001124 }
jjakoa7cd2492003-04-11 09:40:12 +00001125
jjako52c24142002-12-16 13:33:51 +00001126 gtp_free(gsn); /* Clean up the gsn instance */
1127
jjakoa7cd2492003-04-11 09:40:12 +00001128 if (options.createif)
1129 tun_free(tun);
jjako7b8fad42003-07-07 14:37:42 +00001130
1131 if (0 == state)
1132 exit(1); /* Indicate error */
jjako52c24142002-12-16 13:33:51 +00001133
jjakoa7cd2492003-04-11 09:40:12 +00001134 return 0;
jjako52c24142002-12-16 13:33:51 +00001135}
1136