diff options
Diffstat (limited to 'sgsnemu/sgsnemu.c')
-rw-r--r-- | sgsnemu/sgsnemu.c | 1141 |
1 files changed, 567 insertions, 574 deletions
diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c index 1cdfcac..99f0366 100644 --- a/sgsnemu/sgsnemu.c +++ b/sgsnemu/sgsnemu.c @@ -1,6 +1,6 @@ /* * OpenGGSN - Gateway GPRS Support Node - * Copyright (C) 2002 Mondru AB. + * Copyright (C) 2002, 2003 Mondru AB. * * The contents of this file may be used under the terms of the GNU * General Public License Version 2, provided that the above copyright @@ -21,7 +21,7 @@ #ifdef __linux__ -#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */ +#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */ #endif @@ -52,38 +52,59 @@ #include <time.h> #include "tun.h" +#include "ippool.h" +#include "syserr.h" #include "../gtp/pdp.h" #include "../gtp/gtp.h" #include "cmdline.h" -#define SGSNEMU_BUFSIZE 1024 +#define IPADDRLEN 256 /* Character length of addresses */ +#define MAXCONTEXTS 16 /* Max number of allowed contexts */ -/* State variable */ -/* 0: Idle */ -/* 1: Wait_connect */ -/* 2: Connected */ -/* 3: Wait_disconnect */ +/* HASH tables for IP address allocation */ +struct iphash_t { + uint8_t inuse; /* 0=free. 1=used by somebody */ + struct iphash_t *ipnext; + struct pdp_t *pdp; + struct in_addr addr; +}; +struct iphash_t iparr[MAXCONTEXTS]; +struct iphash_t *iphash[MAXCONTEXTS]; + +/* State variable used for ping */ +/* 0: Idle */ +/* 1: Wait_connect */ +/* 2: Connected */ +/* 3: Wait_disconnect */ int state = 0; +struct gsn_t *gsn = NULL; /* GSN instance */ +struct tun_t *tun = NULL; /* TUN instance */ int maxfd = 0; /* For select() */ -int tun_fd = -1; /* Network file descriptor */ -struct tun_t *tun; /* TUN instance */ -struct tun_t *tun1, *tun2; /* TUN instance for client */ -int tun_fd1 = -1; /* Network file descriptor */ -int tun_fd2 = -1; /* Network file descriptor */ - -/* Variables matching program configuration parameters */ -int debug; /* Print debug messages */ -struct in_addr net, mask; /* Network interface */ -int createif; /* Create local network interface */ -char *ipup, *ipdown; /* Filename of scripts */ -/* int defaultroute; Set up default route */ -struct in_addr pinghost; /* Remote ping host */ -int pingrate, pingsize, pingcount, pingquiet; -struct in_addr listen_, remote; -struct in_addr dns; -int contexts; /* Number of contexts to create */ -int timelimit; /* Number of seconds to be connected */ + +/* Struct with local versions of gengetopt options */ +struct { + int debug; /* Print debug messages */ + int createif; /* Create local network interface */ + char *ipup, *ipdown; /* Filename of scripts */ + int defaultroute; /* Set up default route */ + struct in_addr pinghost; /* Remote ping host */ + int pingrate; + int pingsize; + int pingcount; + int pingquiet; + struct in_addr listen; + struct in_addr remote; + struct in_addr dns; + int contexts; /* Number of contexts to create */ + int timelimit; /* Number of seconds to be connected */ + char *statedir; + uint64_t imsi; + struct ul255_t pco; + struct ul255_t qos; + struct ul255_t apn; + struct ul16_t msisdn; +} options; /* Definitions to use for PING. Most of the ping code was derived from */ @@ -123,6 +144,359 @@ int tsum = 0; int pingseq = 0; /* Ping sequence counter */ struct timeval firstping; +int ipset(struct iphash_t *ipaddr, struct in_addr *addr) { + int hash = ippool_hash4(addr) % MAXCONTEXTS; + struct iphash_t *h; + struct iphash_t *prev = NULL; + ipaddr->ipnext = NULL; + ipaddr->addr.s_addr = addr->s_addr; + for (h = iphash[hash]; h; h = h->ipnext) + prev = h; + if (!prev) + iphash[hash] = ipaddr; + else + prev->ipnext = ipaddr; + return 0; +} + +int ipdel(struct iphash_t *ipaddr) { + int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS; + struct iphash_t *h; + struct iphash_t *prev = NULL; + for (h = iphash[hash]; h; h = h->ipnext) { + if (h == ipaddr) { + if (!prev) + iphash[hash] = h->ipnext; + else + prev->ipnext = h->ipnext; + return 0; + } + prev = h; + } + return EOF; /* End of linked list and not found */ +} + +int ipget(struct iphash_t **ipaddr, struct in_addr *addr) { + int hash = ippool_hash4(addr) % MAXCONTEXTS; + struct iphash_t *h; + for (h = iphash[hash]; h; h = h->ipnext) { + if ((h->addr.s_addr == addr->s_addr)) { + *ipaddr = h; + return 0; + } + } + return EOF; /* End of linked list and not found */ +} + + +/* Used to write process ID to file. Assume someone else will delete */ +void log_pid(char *pidfile) { + FILE *file; + mode_t oldmask; + + oldmask = umask(022); + file = fopen(pidfile, "w"); + umask(oldmask); + if(!file) + return; + fprintf(file, "%d\n", getpid()); + fclose(file); +} + + +int process_options(int argc, char **argv) { + /* gengeopt declarations */ + struct gengetopt_args_info args_info; + + struct hostent *host; + int n; + + if (cmdline_parser (argc, argv, &args_info) != 0) + return -1; + if (args_info.debug_flag) { + printf("remote: %s\n", args_info.remote_arg); + printf("listen: %s\n", args_info.listen_arg); + printf("conf: %s\n", args_info.conf_arg); + printf("fg: %d\n", args_info.fg_flag); + printf("debug: %d\n", args_info.debug_flag); + printf("imsi: %s\n", args_info.imsi_arg); + printf("qos: %#08x\n", args_info.qos_arg); + printf("apn: %s\n", args_info.apn_arg); + printf("msisdn: %s\n", args_info.msisdn_arg); + printf("uid: %s\n", args_info.uid_arg); + printf("pwd: %s\n", args_info.pwd_arg); + printf("pidfile: %s\n", args_info.pidfile_arg); + printf("statedir: %s\n", args_info.statedir_arg); + printf("dns: %s\n", args_info.dns_arg); + printf("contexts: %d\n", args_info.contexts_arg); + printf("timelimit: %d\n", args_info.timelimit_arg); + printf("createif: %d\n", args_info.createif_flag); + printf("ipup: %s\n", args_info.ipup_arg); + printf("ipdown: %s\n", args_info.ipdown_arg); + printf("defaultroute: %d\n", args_info.defaultroute_flag); + printf("pinghost: %s\n", args_info.pinghost_arg); + printf("pingrate: %d\n", args_info.pingrate_arg); + printf("pingsize: %d\n", args_info.pingsize_arg); + printf("pingcount: %d\n", args_info.pingcount_arg); + printf("pingquiet: %d\n", args_info.pingquiet_flag); + } + + /* Try out our new parser */ + + if (args_info.conf_arg) { + if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0) != 0) + return -1; + if (args_info.debug_flag) { + printf("cmdline_parser_configfile\n"); + printf("remote: %s\n", args_info.remote_arg); + printf("listen: %s\n", args_info.listen_arg); + printf("conf: %s\n", args_info.conf_arg); + printf("fg: %d\n", args_info.fg_flag); + printf("debug: %d\n", args_info.debug_flag); + printf("imsi: %s\n", args_info.imsi_arg); + printf("qos: %#08x\n", args_info.qos_arg); + printf("apn: %s\n", args_info.apn_arg); + printf("msisdn: %s\n", args_info.msisdn_arg); + printf("uid: %s\n", args_info.uid_arg); + printf("pwd: %s\n", args_info.pwd_arg); + printf("pidfile: %s\n", args_info.pidfile_arg); + printf("statedir: %s\n", args_info.statedir_arg); + printf("dns: %s\n", args_info.dns_arg); + printf("contexts: %d\n", args_info.contexts_arg); + printf("timelimit: %d\n", args_info.timelimit_arg); + printf("createif: %d\n", args_info.createif_flag); + printf("ipup: %s\n", args_info.ipup_arg); + printf("ipdown: %s\n", args_info.ipdown_arg); + printf("defaultroute: %d\n", args_info.defaultroute_flag); + printf("pinghost: %s\n", args_info.pinghost_arg); + printf("pingrate: %d\n", args_info.pingrate_arg); + printf("pingsize: %d\n", args_info.pingsize_arg); + printf("pingcount: %d\n", args_info.pingcount_arg); + printf("pingquiet: %d\n", args_info.pingquiet_flag); + } + } + + /* Handle each option */ + + /* foreground */ + /* If fg flag not given run as a daemon */ + if (!args_info.fg_flag) + { + closelog(); + /* Close the standard file descriptors. Why? */ + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + freopen("/dev/null", "r", stdin); + daemon(0, 0); + /* Open log again. This time with new pid */ + openlog(PACKAGE, LOG_PID, LOG_DAEMON); + } + + /* debug */ + options.debug = args_info.debug_flag; + + /* pidfile */ + /* This has to be done after we have our final pid */ + if (args_info.pidfile_arg) { + log_pid(args_info.pidfile_arg); + } + + /* dns */ + /* If no dns option is given use system default */ + /* Do hostname lookup to translate hostname to IP address */ + printf("\n"); + if (args_info.dns_arg) { + if (!(host = gethostbyname(args_info.dns_arg))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid DNS address: %s!", args_info.dns_arg); + return -1; + } + else { + memcpy(&options.dns.s_addr, host->h_addr, host->h_length); + _res.nscount = 1; + _res.nsaddr_list[0].sin_addr = options.dns; + printf("Using DNS server: %s (%s)\n", + args_info.dns_arg, inet_ntoa(options.dns)); + } + } + else { + options.dns.s_addr= 0; + printf("Using default DNS server\n"); + } + + /* listen */ + /* If no listen option is specified listen to any local port */ + /* Do hostname lookup to translate hostname to IP address */ + if (args_info.listen_arg) { + if (!(host = gethostbyname(args_info.listen_arg))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid listening address: %s!", args_info.listen_arg); + return -1; + } + else { + memcpy(&options.listen.s_addr, host->h_addr, host->h_length); + printf("Local IP address is: %s (%s)\n", + args_info.listen_arg, inet_ntoa(options.listen)); + } + } + else { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Listening address must be specified: %s!", args_info.listen_arg); + return -1; + } + + + /* remote */ + /* If no remote option is specified terminate */ + /* Do hostname lookup to translate hostname to IP address */ + if (args_info.remote_arg) { + if (!(host = gethostbyname(args_info.remote_arg))) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid remote address: %s!", args_info.remote_arg); + return -1; + } + else { + memcpy(&options.remote.s_addr, host->h_addr, host->h_length); + printf("Remote IP address is: %s (%s)\n", + args_info.remote_arg, inet_ntoa(options.remote)); + } + } + else { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "No remote address given!"); + return -1; + } + + + /* imsi */ + if (strlen(args_info.imsi_arg)!=15) { + printf("Invalid IMSI\n"); + return -1; + } + options.imsi = ((uint64_t) (args_info.imsi_arg[ 0]-48)); + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4; + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8; + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12; + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16; + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20; + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24; + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28; + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32; + options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36; + options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40; + options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44; + options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48; + options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52; + options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56; + + printf("IMSI is: %s (%#08llx)\n", + args_info.imsi_arg, options.imsi); + + + /* qos */ + options.qos.l = 3; + options.qos.v[2] = (args_info.qos_arg) & 0xff; + options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff; + options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff; + + /* contexts */ + if (args_info.contexts_arg > MAXCONTEXTS) { + printf("Contexts has to be less than %d\n", MAXCONTEXTS); + return -1; + } + options.contexts = args_info.contexts_arg; + + /* Timelimit */ + options.timelimit = args_info.timelimit_arg; + + /* apn */ + if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) { + printf("Invalid APN\n"); + return -1; + } + options.apn.l = strlen(args_info.apn_arg) + 1; + options.apn.v[0] = (char) strlen(args_info.apn_arg); + strncpy(&options.apn.v[1], args_info.apn_arg, sizeof(options.apn.v)-1); + printf("Using APN: %s\n", args_info.apn_arg); + + /* msisdn */ + if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) { + printf("Invalid MSISDN\n"); + return -1; + } + options.msisdn.l = 1; + options.msisdn.v[0] = 0x91; /* International format */ + for(n=0; n<strlen(args_info.msisdn_arg); n++) { + if ((n%2) == 0) { + options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0; + options.msisdn.l += 1; + } + else { + options.msisdn.v[((int)n/2)+1] = + (options.msisdn.v[((int)n/2)+1] & 0x0f) + + (args_info.msisdn_arg[n] - 48) * 16; + } + } + printf("Using MSISDN: %s\n", args_info.msisdn_arg); + + /* UID and PWD */ + /* Might need to also insert stuff like DNS etc. */ + if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)> + (sizeof(options.pco.v)-1)) { + printf("invalid UID and PWD\n"); + return -1; + } + options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10; + options.pco.v[0] = 0x80; /* PPP */ + options.pco.v[1] = 0xc0; /* PAP */ + options.pco.v[2] = 0x23; + options.pco.v[3] = 0x12; /* Length of protocol contents */ + options.pco.v[4] = 0x01; /* Authenticate request */ + options.pco.v[5] = 0x01; + options.pco.v[6] = 0x00; /* MSB of length */ + options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6; + options.pco.v[8] = strlen(args_info.uid_arg); + memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg)); + options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg); + memcpy(&options.pco.v[10+strlen(args_info.uid_arg)], + args_info.pwd_arg, strlen(args_info.pwd_arg)); + + /* createif */ + options.createif = args_info.createif_flag; + + /* ipup */ + options.ipup = args_info.ipup_arg; + + /* ipdown */ + options.ipdown = args_info.ipdown_arg; + + /* statedir */ + options.statedir = args_info.statedir_arg; + + /* defaultroute */ + options.defaultroute = args_info.defaultroute_flag; + + + /* pinghost */ + /* Store ping host as in_addr */ + if (args_info.pinghost_arg) { + if (!inet_aton(args_info.pinghost_arg, &options.pinghost)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Invalid ping host: %s!", args_info.pinghost_arg); + return -1; + } + } + + /* Other ping parameters */ + options.pingrate = args_info.pingrate_arg; + options.pingsize = args_info.pingsize_arg; + options.pingcount = args_info.pingcount_arg; + options.pingquiet = args_info.pingquiet_flag; + + return 0; + +} + int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) { int i; @@ -175,18 +549,20 @@ int ping_timeout(struct timeval *tp) { struct timezone tz; struct timeval tv; int diff; - if ((pinghost.s_addr) && (2 == state) && - ((pingseq < pingcount) || (pingcount == 0))) { + if ((options.pinghost.s_addr) && (2 == state) && + ((pingseq < options.pingcount) || (options.pingcount == 0))) { gettimeofday(&tv, &tz); - diff = 1000000 / pingrate * pingseq - + diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */ tp->tv_sec = 0; if (diff > 0) tp->tv_usec = diff; - else + else { /* For some reason we get packet loss if set to zero */ - tp->tv_usec = 100000 / pingrate; /* 10 times pingrate */ + tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */ + tp->tv_usec = 0; + } } return 0; } @@ -201,7 +577,7 @@ int ping_finish() elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) + (tv.tv_usec - firstping.tv_usec); /* Microseconds */ printf("\n"); - printf("\n----%s PING Statistics----\n", inet_ntoa(pinghost)); + printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost)); printf("%d packets transmitted in %.3f seconds, ", ntransmitted, elapsed / 1000000.0); printf("%d packets received, ", nreceived ); @@ -214,7 +590,7 @@ int ping_finish() ntransmitted)); } printf("\n"); - if (debug) printf("%d packets received in total\n", ntreceived ); + if (options.debug) printf("%d packets received in total\n", ntreceived ); if (nreceived && tsum) printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n", tmin/1000.0, @@ -238,7 +614,7 @@ int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) { src.s_addr = pingpack->src; gettimeofday(&tv, &tz); - if (debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec); + if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec); if (len < CREATEPING_IP + CREATEPING_ICMP) { printf("packet too short (%d bytes) from %s\n", len, @@ -248,21 +624,21 @@ int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) { ntreceived++; if (pingpack->protocol != 1) { - if (!pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n", + if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n", len, inet_ntoa(src), pingpack->protocol, print_ipprot(pingpack->protocol)); return 0; } if (pingpack->type != 0) { - if (!pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n", + if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n", len, inet_ntoa(src), pingpack->type, print_icmptype(pingpack->type), pingpack->code); return 0; } nreceived++; - if (!pingquiet) printf("%d bytes from %s: icmp_seq=%d", len, + if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len, inet_ntoa(src), ntohs(pingpack->seq)); if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) { @@ -281,11 +657,11 @@ int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) { if( triptime > tmax ) tmax = triptime; - if (!pingquiet) printf(" time=%.3f ms\n", triptime/1000.0); + if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0); } else - if (!pingquiet) printf("\n"); + if (!options.pingquiet) printf("\n"); return 0; } @@ -305,11 +681,9 @@ int create_ping(void *gsn, struct pdp_t *pdp, struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP]; if (datasize > CREATEPING_MAX) { - fprintf(stderr, "%s: Ping size to large: %d!\n", - PACKAGE, datasize); - syslog(LOG_ERR, "Ping size to large: %d!", - datasize); - exit(1); + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Ping size to large: %d!", datasize); + return -1; } memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */ @@ -366,130 +740,72 @@ int create_ping(void *gsn, struct pdp_t *pdp, pack.checksum = ~sum; ntransmitted++; - return gtp_gpdu(gsn, pdp, &pack, 28 + datasize); } -/* Used to write process ID to file. Assume someone else will delete */ -void log_pid(char *pidfile) { - FILE *file; - mode_t oldmask; - - oldmask = umask(022); - file = fopen(pidfile, "w"); - umask(oldmask); - if(!file) - return; - fprintf(file, "%d\n", getpid()); - fclose(file); +int delete_context(struct pdp_t *pdp) { + + if (tun && options.ipdown) tun_runscript(tun, options.ipdown); + + ipdel((struct iphash_t*) pdp->peer); + memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */ + return 0; } -int delete_context(struct pdp_t *pdp) { - char buf[SGSNEMU_BUFSIZE]; - if ((createif) && (pdp->ipif!=0)) { - tun_freetun((struct tun_t*) pdp->ipif); - - /* Clean up locally */ - if (pdp->ipif == tun1) { - printf("Deleting tun interface\n"); - tun_fd1=-1; - } - if (pdp->ipif == tun2) { - printf("Deleting tun interface\n"); - tun_fd2=-1; - } + +/* Callback for receiving messages from tun */ +int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) { + struct iphash_t *ipm; + struct in_addr src; + struct tun_packet_t *iph = (struct tun_packet_t*) pack; + + src.s_addr = iph->src; + + if (ipget(&ipm, &src)) { + printf("Received packet without a valid source address!!!\n"); + return 0; } - if (ipdown) { - /* system("ipdown /dev/tun0 192.168.0.10"); */ - snprintf(buf, sizeof(buf), "%s %s %hu.%hu.%hu.%hu", - ipdown, - ((struct tun_t*) pdp->ipif)->devname, - pdp->eua.v[2], pdp->eua.v[3], pdp->eua.v[4], pdp->eua.v[5]); - if (debug) printf("%s\n", buf); - system(buf); - } - - pdp_ipdel(pdp); + if (ipm->pdp) /* Check if a peer protocol is defined */ + gtp_gpdu(gsn, ipm->pdp, pack, len); return 0; } int create_pdp_conf(struct pdp_t *pdp, int cause) { - char buf[SGSNEMU_BUFSIZE]; - char snet[SGSNEMU_BUFSIZE]; - char smask[SGSNEMU_BUFSIZE]; - - printf("Received create PDP context response. Cause value: %d\n", cause); - if ((cause == 128) && (pdp->eua.l == 6)) { - - if (!createif) { - pdp->ipif = tun1; - } - else { - printf("Setting up interface and routing\n"); - if ((tun_fd = tun_newtun((struct tun_t**) &pdp->ipif)) > maxfd) - maxfd = tun_fd; - - /* HACK: Only support select of up to two tun interfaces */ - if (NULL == tun1) { - tun1 = pdp->ipif; - tun_fd1 = tun1->fd; - } - else { - tun2 = pdp->ipif; - tun_fd2 = tun2->fd; - } - - /*system("/sbin/ifconfig tun0 192.168.0.10");*/ - snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %hu.%hu.%hu.%hu", - ((struct tun_t*) pdp->ipif)->devname, - pdp->eua.v[2], pdp->eua.v[3], pdp->eua.v[4], pdp->eua.v[5]); - /* if (debug) */ printf("%s\n", buf); - system(buf); - - /* system("route add -host 192.168.0.10 dev tun0"); */ - /* It seams as if we do not need to set up a route to a p-t-p interface - snprintf(buf, sizeof(buf), - "/sbin/route add -host %hu.%hu.%hu.%hu dev %s", - pdp->eua.v[2], pdp->eua.v[3], pdp->eua.v[4], pdp->eua.v[5], - ((struct tun_t*) pdp->ipif)->devname); - if (debug) printf("%s\n", buf); - system(buf);*/ - - /*if (defaultroute) {*/ - strncpy(snet, inet_ntoa(net), sizeof(snet)); - strncpy(smask, inet_ntoa(mask), sizeof(smask)); - /* system("route add -net 0.0.0.0 netmask 0.0.0.0 gw 192.168.0.1"); */ - snprintf(buf, sizeof(buf), - "/sbin/route add -net %s netmask %s gw %hu.%hu.%hu.%hu", - snet, smask, - pdp->eua.v[2], pdp->eua.v[3], pdp->eua.v[4], pdp->eua.v[5]); - /* if (debug) */ printf("%s\n", buf); - system(buf); - /*}*/ - - if (ipup) { - /* system("ipup /dev/tun0 192.168.0.10"); */ - snprintf(buf, sizeof(buf), "%s %s %hu.%hu.%hu.%hu", - ipup, - ((struct tun_t*) pdp->ipif)->devname, - pdp->eua.v[2], pdp->eua.v[3], pdp->eua.v[4], pdp->eua.v[5]); - if (debug) printf("%s\n", buf); - system(buf); - } - - } - - pdp_ipset(pdp, pdp->ipif, &pdp->eua); + struct in_addr addr; - state = 2; /* Connected */ + if (cause != 128) { + printf("Received create PDP context response. Cause value: %d\n", cause); + state = 0; + return EOF; /* Not what we expected */ } - else { + + if (pdp_euaton(&pdp->eua, &addr)) { + printf("Received create PDP context response. Cause value: %d\n", cause); state = 0; + return EOF; /* Not a valid IP address */ } - printf("\n"); + printf("Received create PDP context response. IP address: %s\n", + inet_ntoa(addr)); + + if (options.createif) { + struct in_addr m; + inet_aton("255.255.255.255", &m); + /* printf("Setting up interface and routing\n");*/ + tun_addaddr(tun, &addr, &addr, &m); + if (options.defaultroute) { + struct in_addr rm; + rm.s_addr = 0; + tun_addroute(tun, &rm, &addr, &rm); + } + if (options.ipup) tun_runscript(tun, options.ipup); + } + + ipset((struct iphash_t*) pdp->peer, &addr); + + state = 2; /* Connected */ return 0; } @@ -524,23 +840,6 @@ int conf(int type, int cause, struct pdp_t* pdp, void *aid) { } } -int encaps_gtp_client(void *gsn, struct tun_t *tun, void *pack, unsigned len) { - /* Special client version which checks for source address instead */ - struct pdp_t *pdp; - struct in_addr addr; - struct ul66_t eua; - /*printf("encaps_gtp. Packet received: forwarding to gtp.\n");*/ - /* First we need to extract the IP destination address */ - memcpy(&addr.s_addr, pack+12, 4); /* This ought to be dest addr */ - pdp_ntoeua(&addr, &eua); - if (pdp_ipget(&pdp, tun, &eua) == 0) { - return gtp_gpdu((struct gsn_t*) gsn, pdp, pack, len); - } - else { - printf("Received packet without a valid source address!!!\n"); - return 0; - } -} int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) { /* printf("encaps_tun. Packet received: forwarding to tun\n");*/ @@ -549,420 +848,119 @@ int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) { int main(int argc, char **argv) { - /* gengeopt declarations */ - struct gengetopt_args_info args_info; - - - struct hostent *host; - int gtpfd = -1; /* Network file descriptor */ - struct gsn_t *gsn; /* GSN instance */ fd_set fds; /* For select() */ struct timeval idleTime; /* How long to select() */ - struct pdp_t *pdp[50]; - int n; /* For counter */ - int starttime; /* Time program was started */ + struct pdp_t *pdp; + int n; + int starttime = time(NULL); /* Time program was started */ struct timezone tz; /* Used for calculating ping times */ struct timeval tv; int diff; - /* function-local options */ - struct ul_t imsi, qos, apn, msisdn; - unsigned char qosh[3], imsih[8], apnh[256], msisdnh[256]; - struct ul255_t pco; - uint64_t imsi3; - /* open a connection to the syslog daemon */ /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/ openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON); - if (cmdline_parser (argc, argv, &args_info) != 0) + /* Process options given in configuration file and command line */ + if (process_options(argc, argv)) exit(1); - if (args_info.debug_flag) { - printf("remote: %s\n", args_info.remote_arg); - printf("listen: %s\n", args_info.listen_arg); - printf("conf: %s\n", args_info.conf_arg); - printf("fg: %d\n", args_info.fg_flag); - printf("debug: %d\n", args_info.debug_flag); - printf("imsi: %s\n", args_info.imsi_arg); - printf("qos: %#08x\n", args_info.qos_arg); - printf("apn: %s\n", args_info.apn_arg); - printf("msisdn: %s\n", args_info.msisdn_arg); - printf("uid: %s\n", args_info.uid_arg); - printf("pwd: %s\n", args_info.pwd_arg); - printf("pidfile: %s\n", args_info.pidfile_arg); - printf("statedir: %s\n", args_info.statedir_arg); - printf("dns: %s\n", args_info.dns_arg); - printf("contexts: %d\n", args_info.contexts_arg); - printf("timelimit: %d\n", args_info.timelimit_arg); - printf("createif: %d\n", args_info.createif_flag); - printf("ipup: %s\n", args_info.ipup_arg); - printf("ipdown: %s\n", args_info.ipdown_arg); - /*printf("defaultroute: %d\n", args_info.defaultroute_flag);*/ - printf("net: %s\n", args_info.net_arg); - printf("mask: %s\n", args_info.mask_arg); - printf("pinghost: %s\n", args_info.pinghost_arg); - printf("pingrate: %d\n", args_info.pingrate_arg); - printf("pingsize: %d\n", args_info.pingsize_arg); - printf("pingcount: %d\n", args_info.pingcount_arg); - printf("pingquiet: %d\n", args_info.pingquiet_flag); - } - /* Try out our new parser */ - - if (args_info.conf_arg) { - if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0) != 0) - exit(1); - if (args_info.debug_flag) { - printf("cmdline_parser_configfile\n"); - printf("remote: %s\n", args_info.remote_arg); - printf("listen: %s\n", args_info.listen_arg); - printf("conf: %s\n", args_info.conf_arg); - printf("fg: %d\n", args_info.fg_flag); - printf("debug: %d\n", args_info.debug_flag); - printf("imsi: %s\n", args_info.imsi_arg); - printf("qos: %#08x\n", args_info.qos_arg); - printf("apn: %s\n", args_info.apn_arg); - printf("msisdn: %s\n", args_info.msisdn_arg); - printf("uid: %s\n", args_info.uid_arg); - printf("pwd: %s\n", args_info.pwd_arg); - printf("pidfile: %s\n", args_info.pidfile_arg); - printf("statedir: %s\n", args_info.statedir_arg); - printf("dns: %s\n", args_info.dns_arg); - printf("contexts: %d\n", args_info.contexts_arg); - printf("timelimit: %d\n", args_info.timelimit_arg); - printf("createif: %d\n", args_info.createif_flag); - printf("ipup: %s\n", args_info.ipup_arg); - printf("ipdown: %s\n", args_info.ipdown_arg); - /*printf("defaultroute: %d\n", args_info.defaultroute_flag);*/ - printf("net: %s\n", args_info.net_arg); - printf("mask: %s\n", args_info.mask_arg); - printf("pinghost: %s\n", args_info.pinghost_arg); - printf("pingrate: %d\n", args_info.pingrate_arg); - printf("pingsize: %d\n", args_info.pingsize_arg); - printf("pingcount: %d\n", args_info.pingcount_arg); - printf("pingquiet: %d\n", args_info.pingquiet_flag); - } - } - - /* Handle each option */ - - /* foreground */ - /* If fg flag not given run as a daemon */ - if (!args_info.fg_flag) - { - closelog(); - /* Close the standard file descriptors. Why? */ - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); - freopen("/dev/null", "r", stdin); - daemon(0, 0); - /* Open log again. This time with new pid */ - openlog(PACKAGE, LOG_PID, LOG_DAEMON); - } - - /* debug */ - debug = args_info.debug_flag; - - /* pidfile */ - /* This has to be done after we have our final pid */ - if (args_info.pidfile_arg) { - log_pid(args_info.pidfile_arg); - } - - /* dns */ - /* If no dns option is given use system default */ - /* Do hostname lookup to translate hostname to IP address */ - printf("\n"); - if (args_info.dns_arg) { - if (!(host = gethostbyname(args_info.dns_arg))) { - fprintf(stderr, "%s: Invalid dns address: %s!\n", - PACKAGE, args_info.dns_arg); - syslog(LOG_ERR, "Invalid dns address: %s!", - args_info.dns_arg); - exit(1); - } - else { - memcpy(&dns.s_addr, host->h_addr, host->h_length); - _res.nscount = 1; - _res.nsaddr_list[0].sin_addr = dns; - printf("Using DNS server: %s (%s)\n", args_info.dns_arg, inet_ntoa(dns)); - } - } - else { - dns.s_addr= 0; - printf("Using default DNS server\n"); - } - - /* listen */ - /* If no listen option is specified listen to any local port */ - /* Do hostname lookup to translate hostname to IP address */ - if (args_info.listen_arg) { - if (!(host = gethostbyname(args_info.listen_arg))) { - fprintf(stderr, "%s: Invalid listening address: %s!\n", - PACKAGE, args_info.listen_arg); - syslog(LOG_ERR, "Invalid listening address: %s!", - args_info.listen_arg); - exit(1); - } - else { - memcpy(&listen_.s_addr, host->h_addr, host->h_length); - printf("Local IP address is: %s (%s)\n", args_info.listen_arg, inet_ntoa(listen_)); - } - } - else { - fprintf(stderr, "%s: Listening address must be specified: %s!\n", - PACKAGE, args_info.listen_arg); - syslog(LOG_ERR, "Listening address must be specified: %s!", - args_info.listen_arg); - exit(1); - } - - - /* remote */ - /* If no remote option is specified terminate */ - /* Do hostname lookup to translate hostname to IP address */ - if (args_info.remote_arg) { - if (!(host = gethostbyname(args_info.remote_arg))) { - fprintf(stderr, "%s: Invalid remote address: %s!\n", - PACKAGE, args_info.remote_arg); - syslog(LOG_ERR, "Invalid remote address: %s!", - args_info.remote_arg); - exit(1); - } - else { - memcpy(&remote.s_addr, host->h_addr, host->h_length); - printf("Remote IP address is: %s (%s)\n", args_info.remote_arg, inet_ntoa(remote)); - } - } - else { - fprintf(stderr, "%s: No remote address given!\n", - PACKAGE); - syslog(LOG_ERR, "No remote address given!"); - exit(1); - } - - - /* imsi */ - if (strlen(args_info.imsi_arg)!=15) { - printf("Invalid IMSI\n"); - exit(1); - } - imsi.l = 8; - imsi.v = imsih; - imsi.v[0] = args_info.imsi_arg[0]-48 + (args_info.imsi_arg[1]-48)*16; - imsi.v[1] = args_info.imsi_arg[2]-48 + (args_info.imsi_arg[3]-48)*16; - imsi.v[2] = args_info.imsi_arg[4]-48 + (args_info.imsi_arg[5]-48)*16; - imsi.v[3] = args_info.imsi_arg[6]-48 + (args_info.imsi_arg[7]-48)*16; - imsi.v[4] = args_info.imsi_arg[8]-48 + (args_info.imsi_arg[9]-48)*16; - imsi.v[5] = args_info.imsi_arg[10]-48 + (args_info.imsi_arg[11]-48)*16; - imsi.v[6] = args_info.imsi_arg[12]-48 + (args_info.imsi_arg[13]-48)*16; - imsi.v[7] = args_info.imsi_arg[14]-48 + 0*16; - - if (imsi.l > sizeof(imsi3)) { - printf("Invalid IMSI\n"); - exit(1); - } - else { - memcpy(&imsi3, imsi.v, imsi.l); - printf("IMSI is: %s (%#08llx)\n", args_info.imsi_arg, imsi3); - } - - /* qos */ - qos.l = 3; - qos.v = qosh; - qos.v[2] = (args_info.qos_arg) & 0xff; - qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff; - qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff; - - /* contexts */ - if (args_info.contexts_arg>16) { - printf("Contexts has to be less than 16\n"); - exit(1); - } - contexts = args_info.contexts_arg; - - /* Timelimit */ - timelimit = args_info.timelimit_arg; - starttime = time(NULL); - - /* apn */ - if (strlen(args_info.apn_arg)>255) { - printf("Invalid APN\n"); - exit(1); - } - apn.l = strlen(args_info.apn_arg) + 1; - apn.v = apnh; - apn.v[0] = (char) strlen(args_info.apn_arg); - strncpy(&apn.v[1], args_info.apn_arg, 255); - printf("Using APN: %s\n", args_info.apn_arg); - - /* msisdn */ - if (strlen(args_info.msisdn_arg)>255) { - printf("Invalid MSISDN\n"); - exit(1); - } - msisdn.l = 1; - msisdn.v = msisdnh; - msisdn.v[0] = 0x91; /* International format */ - for(n=0; n<strlen(args_info.msisdn_arg); n++) { - if ((n%2) == 0) { - msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0; - msisdn.l += 1; - } - else { - msisdn.v[((int)n/2)+1] = (msisdn.v[((int)n/2)+1] & 0x0f) + (args_info.msisdn_arg[n] - 48) * 16; - } - } - printf("Using MSISDN: %s\n", args_info.msisdn_arg); - - /* UID and PWD */ - /* Might need to also insert stuff like DNS etc. */ - if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>255) { - printf("invalid UID and PWD\n"); + printf("\nInitialising GTP library\n"); + if (gtp_new(&gsn, options.statedir, &options.listen)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to create gtp"); exit(1); } - pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10; - pco.v[0] = 0x80; /* PPP */ - pco.v[1] = 0xc0; - pco.v[2] = 0x23; /* PAP */ - pco.v[3] = 0x12; - pco.v[4] = 0x01; /* Authenticate request */ - pco.v[5] = 0x01; - pco.v[6] = 0x00; /* MSB of length */ - pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6; - pco.v[8] = strlen(args_info.uid_arg); - memcpy(&pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg)); - pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg); - memcpy(&pco.v[10+strlen(args_info.uid_arg)], args_info.pwd_arg, strlen(args_info.pwd_arg)); - - /* createif */ - createif = args_info.createif_flag; - - /* ipup */ - ipup = args_info.ipup_arg; - - /* ipdown */ - ipdown = args_info.ipdown_arg; - - /* defaultroute - defaultroute = args_info.defaultroute_flag;*/ - - /* net */ - /* Store net as in_addr */ - if (args_info.net_arg) { - if (!inet_aton(args_info.net_arg, &net)) { - fprintf(stderr, "%s: Invalid network address: %s!\n", - PACKAGE, args_info.net_arg); - syslog(LOG_ERR, "Invalid network address: %s!", - args_info.net_arg); - exit(1); - } - } + if (gsn->fd > maxfd) maxfd = gsn->fd; - /* mask */ - /* Store mask as in_addr */ - if (args_info.mask_arg) { - if (!inet_aton(args_info.mask_arg, &mask)) { - fprintf(stderr, "%s: Invalid network mask: %s!\n", - PACKAGE, args_info.mask_arg); - syslog(LOG_ERR, "Invalid network mask: %s!", - args_info.mask_arg); - exit(1); - } - } + gtp_set_cb_delete_context(gsn, delete_context); + gtp_set_cb_conf(gsn, conf); + if (options.createif) + gtp_set_cb_gpdu(gsn, encaps_tun); + else + gtp_set_cb_gpdu(gsn, encaps_ping); - /* pinghost */ - /* Store ping host as in_addr */ - if (args_info.pinghost_arg) { - if (!inet_aton(args_info.pinghost_arg, &pinghost)) { - fprintf(stderr, "%s: Invalid ping host: %s!\n", - PACKAGE, args_info.pinghost_arg); - syslog(LOG_ERR, "Invalid ping host: %s!", - args_info.pinghost_arg); + if (options.createif) { + printf("Setting up interface\n"); + /* Create a tunnel interface */ + if (tun_new((struct tun_t**) &tun)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Failed to create tun"); exit(1); } + tun_set_cb_ind(tun, cb_tun_ind); + if (tun->fd > maxfd) maxfd = tun->fd; } - /* Other ping parameters */ - pingrate = args_info.pingrate_arg; - pingsize = args_info.pingsize_arg; - pingcount = args_info.pingcount_arg; - pingquiet = args_info.pingquiet_flag; - - printf("\nInitialising GTP library\n"); - if ((gtpfd = gtp_new(&gsn, args_info.statedir_arg, &listen_)) > maxfd) - maxfd = gtpfd; + /* Initialise hash tables */ + memset(&iphash, 0, sizeof(iphash)); + memset(&iparr, 0, sizeof(iparr)); - if ((gtpfd = gtp_fd(gsn)) > maxfd) - maxfd = gtpfd; - - if (createif) - gtp_set_cb_gpdu(gsn, encaps_tun); - else - gtp_set_cb_gpdu(gsn, encaps_ping); - - gtp_set_cb_delete_context(gsn, delete_context); - - gtp_set_cb_conf(gsn, conf); printf("Done initialising GTP library\n\n"); /* See if anybody is there */ printf("Sending off echo request\n"); - if (gtpfd != -1) gtp_echo_req(gsn, &remote); /* See if remote is alive ? */ + gtp_echo_req(gsn, &options.remote); /* See if remote is alive ? */ - for(n=0; n<contexts; n++) { + for(n=0; n<options.contexts; n++) { printf("Setting up PDP context #%d\n", n); + iparr[n].inuse = 1; /* TODO */ - pdp_newpdp(&pdp[n], imsi3, n, NULL); /* Allocated here. Cleaned up in gtp.c: TODO Should be statically allocated! */ - - /* - if (qos.l > sizeof(pdp[n]->qos_req.v)) { - exit(1); - } - else { - pdp[n]->qos_req.l = qos.l; - memcpy(pdp[n]->qos_req.v, qos.v, qos.l); - } - */ - memcpy(pdp[n]->qos_req0, qos.v, qos.l); /* TODO range check */ + /* Allocated here. Cleaned up in gtp.c:*/ + pdp_newpdp(&pdp, options.imsi, n, NULL); + + pdp->peer = &iparr[n]; + pdp->ipif = tun; /* TODO */ + iparr[n].pdp = pdp; + + if (options.qos.l > sizeof(pdp->qos_req0)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big"); + exit(1); + } + else { + memcpy(pdp->qos_req0, options.qos.v, options.qos.l); + } - pdp[n]->selmode = 0x01; /* MS provided APN, subscription not verified */ + pdp->selmode = 0x01; /* MS provided APN, subscription not verified */ - if (apn.l > sizeof(pdp[n]->apn_use.v)) { + if (options.apn.l > sizeof(pdp->apn_use.v)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big"); exit(1); } else { - pdp[n]->apn_use.l = apn.l; - memcpy(pdp[n]->apn_use.v, apn.v, apn.l); + pdp->apn_use.l = options.apn.l; + memcpy(pdp->apn_use.v, options.apn.v, options.apn.l); } - pdp[n]->gsnlc.l = 4; - memcpy(pdp[n]->gsnlc.v, &listen_, 4); - pdp[n]->gsnlu.l = 4; - memcpy(pdp[n]->gsnlu.v, &listen_, 4); + pdp->gsnlc.l = sizeof(options.listen); + memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen)); + pdp->gsnlu.l = sizeof(options.listen); + memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen)); - if (msisdn.l > sizeof(pdp[n]->msisdn.v)) { + if (options.msisdn.l > sizeof(pdp->msisdn.v)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big"); exit(1); } else { - pdp[n]->msisdn.l = msisdn.l; - memcpy(pdp[n]->msisdn.v, msisdn.v, msisdn.l); + pdp->msisdn.l = options.msisdn.l; + memcpy(pdp->msisdn.v, options.msisdn.v, options.msisdn.l); } - ipv42eua(&pdp[n]->eua, NULL); /* Request dynamic IP address */ + ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */ - if (pco.l > sizeof(pdp[n]->pco_req.v)) { + if (options.pco.l > sizeof(pdp->pco_req.v)) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big"); exit(1); } else { - pdp[n]->pco_req.l = pco.l; - memcpy(pdp[n]->pco_req.v, pco.v, pco.l); + pdp->pco_req.l = options.pco.l; + memcpy(pdp->pco_req.v, options.pco.v, options.pco.l); } /* Create context */ /* We send this of once. Retransmissions are handled by gtplib */ - if (gtpfd != -1) gtp_create_context(gsn, pdp[n], NULL, &remote); + gtp_create_context(gsn, pdp, NULL, &options.remote); } state = 1; /* Enter wait_connection state */ @@ -974,55 +972,58 @@ int main(int argc, char **argv) /* Main select loop */ /******************************************************************/ - while ((((starttime + timelimit + 10) > time(NULL)) - || (0 == timelimit)) && (state!=0)) { + while ((((starttime + options.timelimit + 10) > time(NULL)) + || (0 == options.timelimit)) && (state!=0)) { /* Take down client connections at some stage */ - if (((starttime + timelimit) <= time(NULL)) && (0 != timelimit) && (2 == state)) { + if (((starttime + options.timelimit) <= time(NULL)) && + (0 != options.timelimit) && (2 == state)) { state = 3; - for(n=0; n<contexts; n++) { + for(n=0; n<options.contexts; n++) { /* Delete context */ printf("Disconnecting PDP context #%d\n", n); - if (gtpfd != -1) gtp_delete_context(gsn, pdp[n], NULL); - if ((pinghost.s_addr !=0) && ntransmitted) ping_finish(); + gtp_delete_context(gsn, iparr[n].pdp, NULL); + if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish(); } } - - + + diff = 0; + while (( diff<=0 ) && /* Send off an ICMP ping packet */ - if ((pinghost.s_addr) && (2 == state) && - ((pingseq < pingcount) || (pingcount == 0))) { + /*if (*/(options.pinghost.s_addr) && (2 == state) && + ((pingseq < options.pingcount) || (options.pingcount == 0))) { if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */ gettimeofday(&tv, &tz); - diff = 1000000 / pingrate * pingseq - + diff = 1000000 / options.pingrate * pingseq - 1000000 * (tv.tv_sec - firstping.tv_sec) - (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */ if (diff <=0) { - if (debug) printf("Create_ping %d\n", diff); - create_ping(gsn, pdp[pingseq % contexts], - &pinghost, pingseq, pingsize); + if (options.debug) printf("Create_ping %d\n", diff); + create_ping(gsn, iparr[pingseq % options.contexts].pdp, + &options.pinghost, pingseq, options.pingsize); pingseq++; } } + - if (ntransmitted && pingcount && nreceived >= pingcount) + if (ntransmitted && options.pingcount && nreceived >= options.pingcount) ping_finish(); - + FD_ZERO(&fds); - if (tun_fd1 != -1) FD_SET(tun_fd1, &fds); - if (tun_fd2 != -1) FD_SET(tun_fd2, &fds); - if (gtpfd != -1) FD_SET(gtpfd, &fds); + if (tun) FD_SET(tun->fd, &fds); + FD_SET(gsn->fd, &fds); gtp_retranstimeout(gsn, &idleTime); ping_timeout(&idleTime); - - if (debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n", - (int) idleTime.tv_sec, (int) idleTime.tv_usec); - + + if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n", + (int) idleTime.tv_sec, (int) idleTime.tv_usec); + switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) { case -1: - syslog(LOG_ERR, "sgsnemu: select = -1"); + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "Select returned -1"); break; case 0: gtp_retrans(gsn); /* Only retransmit if nothing else */ @@ -1030,30 +1031,22 @@ int main(int argc, char **argv) default: break; } - - if (tun_fd1 != -1 && - FD_ISSET(tun_fd1, &fds) && - tun_decaps(tun1, encaps_gtp_client, gsn) < 0) { - syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun_fd1); - } - - if (tun_fd2 != -1 && - FD_ISSET(tun_fd2, &fds) && - tun_decaps(tun2, encaps_gtp_client, gsn) < 0) { - syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun_fd2); - } - - if (gtpfd != -1 && FD_ISSET(gtpfd, &fds) && - gtp_decaps(gsn) < 0) { - syslog(LOG_ERR, "GTP read failed (gtpfd)=(%d)", gtpfd); + + if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) { + sys_err(LOG_ERR, __FILE__, __LINE__, 0, + "TUN decaps failed"); } + if (FD_ISSET(gsn->fd, &fds)) + gtp_decaps(gsn); } - + gtp_free(gsn); /* Clean up the gsn instance */ - return 0; + if (options.createif) + tun_free(tun); + return 0; } |