blob: 1148755044d110ad0226c47671574bf188cc89ce [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++;
jjako5da68452003-01-28 16:08:47 +0000742 return gtp_gpdu(gsn, pdp, &pack, 28 + datasize);
743}
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 */
774 gtp_gpdu(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000775 return 0;
776}
777
778int create_pdp_conf(struct pdp_t *pdp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000779 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000780
jjakoa7cd2492003-04-11 09:40:12 +0000781 if (cause != 128) {
782 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000783 state = 0;
jjakoa7cd2492003-04-11 09:40:12 +0000784 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000785 }
786
jjakoa7cd2492003-04-11 09:40:12 +0000787 if (pdp_euaton(&pdp->eua, &addr)) {
788 printf("Received create PDP context response. Cause value: %d\n", cause);
789 state = 0;
790 return EOF; /* Not a valid IP address */
791 }
792
793 printf("Received create PDP context response. IP address: %s\n",
794 inet_ntoa(addr));
795
796 if (options.createif) {
797 struct in_addr m;
798 inet_aton("255.255.255.255", &m);
799 /* printf("Setting up interface and routing\n");*/
800 tun_addaddr(tun, &addr, &addr, &m);
801 if (options.defaultroute) {
802 struct in_addr rm;
803 rm.s_addr = 0;
804 tun_addroute(tun, &rm, &addr, &rm);
805 }
806 if (options.ipup) tun_runscript(tun, options.ipup);
807 }
808
809 ipset((struct iphash_t*) pdp->peer, &addr);
810
811 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000812
813 return 0;
814}
815
jjako52c24142002-12-16 13:33:51 +0000816int delete_pdp_conf(struct pdp_t *pdp, int cause) {
817 printf("Received delete PDP context response. Cause value: %d\n", cause);
818 return 0;
819}
820
821int echo_conf(struct pdp_t *pdp, int cause) {
jjako7b8fad42003-07-07 14:37:42 +0000822 if (cause <0) {
jjako5da68452003-01-28 16:08:47 +0000823 printf("Echo request timed out\n");
jjako7b8fad42003-07-07 14:37:42 +0000824 state = 0;
825 }
jjako5da68452003-01-28 16:08:47 +0000826 else
827 printf("Received echo response.\n");
jjako52c24142002-12-16 13:33:51 +0000828 return 0;
829}
830
831int conf(int type, int cause, struct pdp_t* pdp, void *aid) {
832 /* if (cause < 0) return 0; Some error occurred. We don't care */
833 switch (type) {
834 case GTP_ECHO_REQ:
835 return echo_conf(pdp, cause);
836 case GTP_CREATE_PDP_REQ:
837 if (cause !=128) return 0; /* Request not accepted. We don't care */
838 return create_pdp_conf(pdp, cause);
839 case GTP_DELETE_PDP_REQ:
840 if (cause !=128) return 0; /* Request not accepted. We don't care */
841 return delete_pdp_conf(pdp, cause);
842 default:
843 return 0;
844 }
845}
846
jjako52c24142002-12-16 13:33:51 +0000847
848int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
849 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
850 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
851}
852
853int main(int argc, char **argv)
854{
jjako52c24142002-12-16 13:33:51 +0000855 fd_set fds; /* For select() */
856 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +0000857 struct pdp_t *pdp;
858 int n;
859 int starttime = time(NULL); /* Time program was started */
jjako7b8fad42003-07-07 14:37:42 +0000860 int stoptime = 0; /* Time to exit */
861 int pingtimeout = 0; /* Time to print ping statistics */
jjakoafb2a972003-01-29 21:04:13 +0000862
863 struct timezone tz; /* Used for calculating ping times */
864 struct timeval tv;
865 int diff;
jjako52c24142002-12-16 13:33:51 +0000866
jjako52c24142002-12-16 13:33:51 +0000867 /* open a connection to the syslog daemon */
868 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
869 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
870
jjakoa7cd2492003-04-11 09:40:12 +0000871 /* Process options given in configuration file and command line */
872 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +0000873 exit(1);
jjako52c24142002-12-16 13:33:51 +0000874
875 printf("\nInitialising GTP library\n");
jjakoe607f742003-07-06 21:21:30 +0000876 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
jjakoa7cd2492003-04-11 09:40:12 +0000877 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
878 "Failed to create gtp");
879 exit(1);
880 }
881 if (gsn->fd > maxfd) maxfd = gsn->fd;
jjako52c24142002-12-16 13:33:51 +0000882
jjakoa7cd2492003-04-11 09:40:12 +0000883 gtp_set_cb_delete_context(gsn, delete_context);
884 gtp_set_cb_conf(gsn, conf);
885 if (options.createif)
jjako5da68452003-01-28 16:08:47 +0000886 gtp_set_cb_gpdu(gsn, encaps_tun);
887 else
888 gtp_set_cb_gpdu(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +0000889
890 if (options.createif) {
891 printf("Setting up interface\n");
892 /* Create a tunnel interface */
893 if (tun_new((struct tun_t**) &tun)) {
894 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
895 "Failed to create tun");
896 exit(1);
897 }
898 tun_set_cb_ind(tun, cb_tun_ind);
899 if (tun->fd > maxfd) maxfd = tun->fd;
900 }
901
902 /* Initialise hash tables */
903 memset(&iphash, 0, sizeof(iphash));
904 memset(&iparr, 0, sizeof(iparr));
905
jjako52c24142002-12-16 13:33:51 +0000906 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +0000907
908 /* See if anybody is there */
909 printf("Sending off echo request\n");
jjakoa7cd2492003-04-11 09:40:12 +0000910 gtp_echo_req(gsn, &options.remote); /* See if remote is alive ? */
jjako52c24142002-12-16 13:33:51 +0000911
jjakoa7cd2492003-04-11 09:40:12 +0000912 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +0000913 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +0000914 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +0000915
jjakoa7cd2492003-04-11 09:40:12 +0000916 /* Allocated here. Cleaned up in gtp.c:*/
917 pdp_newpdp(&pdp, options.imsi, n, NULL);
918
919 pdp->peer = &iparr[n];
920 pdp->ipif = tun; /* TODO */
921 iparr[n].pdp = pdp;
922
923 if (options.qos.l > sizeof(pdp->qos_req0)) {
924 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +0000925 exit(1);
926 }
927 else {
jjakoa7cd2492003-04-11 09:40:12 +0000928 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000929 }
930
jjakoa7cd2492003-04-11 09:40:12 +0000931 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +0000932
jjakoa7cd2492003-04-11 09:40:12 +0000933 if (options.apn.l > sizeof(pdp->apn_use.v)) {
934 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +0000935 exit(1);
936 }
937 else {
jjakoa7cd2492003-04-11 09:40:12 +0000938 pdp->apn_use.l = options.apn.l;
939 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +0000940 }
941
jjakoa7cd2492003-04-11 09:40:12 +0000942 pdp->gsnlc.l = sizeof(options.listen);
943 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
944 pdp->gsnlu.l = sizeof(options.listen);
945 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +0000946
jjakoa7cd2492003-04-11 09:40:12 +0000947 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
948 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +0000949 exit(1);
950 }
951 else {
jjakoa7cd2492003-04-11 09:40:12 +0000952 pdp->msisdn.l = options.msisdn.l;
953 memcpy(pdp->msisdn.v, options.msisdn.v, options.msisdn.l);
954 }
955
956 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
957
958 if (options.pco.l > sizeof(pdp->pco_req.v)) {
959 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
960 exit(1);
961 }
962 else {
963 pdp->pco_req.l = options.pco.l;
964 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +0000965 }
966
967 /* Create context */
968 /* We send this of once. Retransmissions are handled by gtplib */
jjakoa7cd2492003-04-11 09:40:12 +0000969 gtp_create_context(gsn, pdp, NULL, &options.remote);
jjako52c24142002-12-16 13:33:51 +0000970 }
971
972 state = 1; /* Enter wait_connection state */
973
974 printf("Waiting for response from ggsn........\n\n");
975
jjako5da68452003-01-28 16:08:47 +0000976
jjako52c24142002-12-16 13:33:51 +0000977 /******************************************************************/
978 /* Main select loop */
979 /******************************************************************/
980
jjako7b8fad42003-07-07 14:37:42 +0000981 while ((0 != state) && (5 != state)) {
jjako52c24142002-12-16 13:33:51 +0000982
jjako7b8fad42003-07-07 14:37:42 +0000983 /* Take down client after timeout after disconnect */
984 if ((4 == state) && ((stoptime) <= time(NULL))) {
985 state = 5;
986 }
987
988 /* Take down client after timelimit timeout */
989 if ((2 == state) && (options.timelimit) &&
990 ((starttime + options.timelimit) <= time(NULL))) {
jjako52c24142002-12-16 13:33:51 +0000991 state = 3;
jjako7b8fad42003-07-07 14:37:42 +0000992 }
993
994 /* Take down client after ping timeout */
995 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
996 state = 3;
997 }
998
999 /* Set pingtimeout for later disconnection */
1000 if (options.pingcount && ntransmitted >= options.pingcount) {
1001 pingtimeout = time(NULL) + 5; /* Extra seconds */
1002 }
1003
1004 /* Print statistics if no more ping packets are missing */
1005 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1006 ping_finish();
1007 if (!options.createif)
1008 state = 3;
1009 }
1010
1011 /* Send of disconnect */
1012 if (3 == state) {
1013 state = 4;
1014 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
jjakoa7cd2492003-04-11 09:40:12 +00001015 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +00001016 /* Delete context */
1017 printf("Disconnecting PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +00001018 gtp_delete_context(gsn, iparr[n].pdp, NULL);
1019 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +00001020 }
jjakoafb2a972003-01-29 21:04:13 +00001021 }
jjako7b8fad42003-07-07 14:37:42 +00001022
1023 /* Send of ping packets */
jjakoa7cd2492003-04-11 09:40:12 +00001024 diff = 0;
1025 while (( diff<=0 ) &&
jjako7b8fad42003-07-07 14:37:42 +00001026 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +00001027 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
jjako7b8fad42003-07-07 14:37:42 +00001028 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +00001029 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1030 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +00001031 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +00001032 1000000 * (tv.tv_sec - firstping.tv_sec) -
1033 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1034 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001035 if (options.debug) printf("Create_ping %d\n", diff);
1036 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1037 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001038 pingseq++;
1039 }
jjako52c24142002-12-16 13:33:51 +00001040 }
jjako5da68452003-01-28 16:08:47 +00001041
jjako52c24142002-12-16 13:33:51 +00001042 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001043 if (tun) FD_SET(tun->fd, &fds);
1044 FD_SET(gsn->fd, &fds);
jjako52c24142002-12-16 13:33:51 +00001045
1046 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001047 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001048
1049 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1050 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1051
jjako52c24142002-12-16 13:33:51 +00001052 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1053 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001054 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1055 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001056 break;
1057 case 0:
1058 gtp_retrans(gsn); /* Only retransmit if nothing else */
1059 break;
1060 default:
1061 break;
1062 }
jjakoa7cd2492003-04-11 09:40:12 +00001063
1064 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1065 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1066 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001067 }
1068
jjakoa7cd2492003-04-11 09:40:12 +00001069 if (FD_ISSET(gsn->fd, &fds))
1070 gtp_decaps(gsn);
jjako52c24142002-12-16 13:33:51 +00001071
jjako5da68452003-01-28 16:08:47 +00001072 }
jjakoa7cd2492003-04-11 09:40:12 +00001073
jjako52c24142002-12-16 13:33:51 +00001074 gtp_free(gsn); /* Clean up the gsn instance */
1075
jjakoa7cd2492003-04-11 09:40:12 +00001076 if (options.createif)
1077 tun_free(tun);
jjako7b8fad42003-07-07 14:37:42 +00001078
1079 if (0 == state)
1080 exit(1); /* Indicate error */
jjako52c24142002-12-16 13:33:51 +00001081
jjakoa7cd2492003-04-11 09:40:12 +00001082 return 0;
jjako52c24142002-12-16 13:33:51 +00001083}
1084