fixed compilation warning against gcc-4.4
[openggsn.git] / sgsnemu / sgsnemu.c
blob2675c0feb88d5a53894f181c802c0f5902f5905a
1 /*
2 * OpenGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002, 2003, 2004 Mondru AB.
4 *
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 *
13 * sgsnemu.c
18 #ifdef __linux__
19 #define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
20 #endif
23 #include <syslog.h>
24 #include <ctype.h>
25 #include <netdb.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <sys/wait.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
39 #include <sys/time.h>
40 #include <net/if.h>
41 #include <errno.h>
42 #include <sys/socket.h>
43 #include <resolv.h>
44 #include <time.h>
46 #include "config.h"
47 #include "../lib/tun.h"
48 #include "../lib/ippool.h"
49 #include "../lib/syserr.h"
50 #include "../gtp/pdp.h"
51 #include "../gtp/gtp.h"
52 #include "cmdline.h"
54 #define IPADDRLEN 256 /* Character length of addresses */
55 #define MAXCONTEXTS 1024 /* Max number of allowed contexts */
57 /* HASH tables for IP address allocation */
58 struct iphash_t {
59 uint8_t inuse; /* 0=free. 1=used by somebody */
60 struct iphash_t *ipnext;
61 struct pdp_t *pdp;
62 struct in_addr addr;
64 struct iphash_t iparr[MAXCONTEXTS];
65 struct iphash_t *iphash[MAXCONTEXTS];
67 /* State variable used for ping */
68 /* 0: Idle */
69 /* 1: Wait_connect */
70 /* 2: Connected */
71 /* 3: Done */
72 /* 4: Wait_disconnect */
73 /* 5: Disconnected */
74 int state = 0;
76 struct gsn_t *gsn = NULL; /* GSN instance */
77 struct tun_t *tun = NULL; /* TUN instance */
78 int maxfd = 0; /* For select() */
79 int echoversion = 1; /* First try this version */
81 /* Struct with local versions of gengetopt options */
82 struct {
83 int debug; /* Print debug messages */
84 int createif; /* Create local network interface */
85 struct in_addr netaddr, destaddr, net, mask; /* Network interface */
86 char *ipup, *ipdown; /* Filename of scripts */
87 int defaultroute; /* Set up default route */
88 struct in_addr pinghost; /* Remote ping host */
89 int pingrate;
90 int pingsize;
91 int pingcount;
92 int pingquiet;
93 struct in_addr listen;
94 struct in_addr remote;
95 struct in_addr dns;
96 int contexts; /* Number of contexts to create */
97 int timelimit; /* Number of seconds to be connected */
98 char *statedir;
99 uint64_t imsi;
100 uint8_t nsapi;
101 int gtpversion;
102 struct ul255_t pco;
103 struct ul255_t qos;
104 uint16_t cch;
105 struct ul255_t apn;
106 uint8_t selmode;
107 struct ul16_t msisdn;
108 } options;
111 /* Definitions to use for PING. Most of the ping code was derived from */
112 /* the original ping program by Mike Muuss */
114 /* IP header and ICMP echo header */
115 #define CREATEPING_MAX 2048
116 #define CREATEPING_IP 20
117 #define CREATEPING_ICMP 8
119 struct ip_ping {
120 uint8_t ipver; /* Type and header length*/
121 uint8_t tos; /* Type of Service */
122 uint16_t length; /* Total length */
123 uint16_t fragid; /* Identifier */
124 uint16_t offset; /* Flags and fragment offset */
125 uint8_t ttl; /* Time to live */
126 uint8_t protocol; /* Protocol */
127 uint16_t ipcheck; /* Header checksum */
128 uint32_t src; /* Source address */
129 uint32_t dst; /* Destination */
130 uint8_t type; /* Type and header length*/
131 uint8_t code; /* Code */
132 uint16_t checksum; /* Header checksum */
133 uint16_t ident; /* Identifier */
134 uint16_t seq; /* Sequence number */
135 uint8_t data[CREATEPING_MAX]; /* Data */
136 } __attribute__((packed));
138 /* Statistical values for ping */
139 int nreceived = 0;
140 int ntreceived = 0;
141 int ntransmitted = 0;
142 int tmin = 999999999;
143 int tmax = 0;
144 int tsum = 0;
145 int pingseq = 0; /* Ping sequence counter */
146 struct timeval firstping;
148 int ipset(struct iphash_t *ipaddr, struct in_addr *addr) {
149 int hash = ippool_hash4(addr) % MAXCONTEXTS;
150 struct iphash_t *h;
151 struct iphash_t *prev = NULL;
152 ipaddr->ipnext = NULL;
153 ipaddr->addr.s_addr = addr->s_addr;
154 for (h = iphash[hash]; h; h = h->ipnext)
155 prev = h;
156 if (!prev)
157 iphash[hash] = ipaddr;
158 else
159 prev->ipnext = ipaddr;
160 return 0;
163 int ipdel(struct iphash_t *ipaddr) {
164 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
165 struct iphash_t *h;
166 struct iphash_t *prev = NULL;
167 for (h = iphash[hash]; h; h = h->ipnext) {
168 if (h == ipaddr) {
169 if (!prev)
170 iphash[hash] = h->ipnext;
171 else
172 prev->ipnext = h->ipnext;
173 return 0;
175 prev = h;
177 return EOF; /* End of linked list and not found */
180 int ipget(struct iphash_t **ipaddr, struct in_addr *addr) {
181 int hash = ippool_hash4(addr) % MAXCONTEXTS;
182 struct iphash_t *h;
183 for (h = iphash[hash]; h; h = h->ipnext) {
184 if ((h->addr.s_addr == addr->s_addr)) {
185 *ipaddr = h;
186 return 0;
189 return EOF; /* End of linked list and not found */
193 /* Used to write process ID to file. Assume someone else will delete */
194 void log_pid(char *pidfile) {
195 FILE *file;
196 mode_t oldmask;
198 oldmask = umask(022);
199 file = fopen(pidfile, "w");
200 umask(oldmask);
201 if(!file)
202 return;
203 fprintf(file, "%d\n", (int) getpid());
204 fclose(file);
208 int process_options(int argc, char **argv) {
209 /* gengeopt declarations */
210 struct gengetopt_args_info args_info;
212 struct hostent *host;
213 unsigned int n;
215 if (cmdline_parser (argc, argv, &args_info) != 0)
216 return -1;
217 if (args_info.debug_flag) {
218 if (args_info.remote_arg) printf("remote: %s\n", args_info.remote_arg);
219 if (args_info.listen_arg) printf("listen: %s\n", args_info.listen_arg);
220 if (args_info.conf_arg) printf("conf: %s\n", args_info.conf_arg);
221 printf("debug: %d\n", args_info.debug_flag);
222 if (args_info.imsi_arg) printf("imsi: %s\n", args_info.imsi_arg);
223 printf("qos: %#08x\n", args_info.qos_arg);
224 printf("charging: %#04x\n", args_info.charging_arg);
225 if (args_info.apn_arg) printf("apn: %s\n", args_info.apn_arg);
226 if (args_info.msisdn_arg) printf("msisdn: %s\n", args_info.msisdn_arg);
227 if (args_info.uid_arg) printf("uid: %s\n", args_info.uid_arg);
228 if (args_info.pwd_arg) printf("pwd: %s\n", args_info.pwd_arg);
229 if (args_info.pidfile_arg) printf("pidfile: %s\n", args_info.pidfile_arg);
230 if (args_info.statedir_arg) printf("statedir: %s\n", args_info.statedir_arg);
231 if (args_info.dns_arg) 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 if (args_info.ipup_arg) printf("ipup: %s\n", args_info.ipup_arg);
236 if (args_info.ipdown_arg) printf("ipdown: %s\n", args_info.ipdown_arg);
237 printf("defaultroute: %d\n", args_info.defaultroute_flag);
238 if (args_info.pinghost_arg) 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);
245 /* Try out our new parser */
247 if (args_info.conf_arg) {
248 if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0, 0, 0) != 0)
249 return -1;
250 if (args_info.debug_flag) {
251 printf("cmdline_parser_configfile\n");
252 if (args_info.remote_arg) printf("remote: %s\n", args_info.remote_arg);
253 if (args_info.listen_arg) printf("listen: %s\n", args_info.listen_arg);
254 if (args_info.conf_arg) printf("conf: %s\n", args_info.conf_arg);
255 printf("debug: %d\n", args_info.debug_flag);
256 if (args_info.imsi_arg) printf("imsi: %s\n", args_info.imsi_arg);
257 printf("qos: %#08x\n", args_info.qos_arg);
258 printf("charging: %#04x\n", args_info.charging_arg);
259 if (args_info.apn_arg) printf("apn: %s\n", args_info.apn_arg);
260 if (args_info.msisdn_arg) printf("msisdn: %s\n", args_info.msisdn_arg);
261 if (args_info.uid_arg) printf("uid: %s\n", args_info.uid_arg);
262 if (args_info.pwd_arg) printf("pwd: %s\n", args_info.pwd_arg);
263 if (args_info.pidfile_arg) printf("pidfile: %s\n", args_info.pidfile_arg);
264 if (args_info.statedir_arg) printf("statedir: %s\n", args_info.statedir_arg);
265 if (args_info.dns_arg) 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 if (args_info.ipup_arg) printf("ipup: %s\n", args_info.ipup_arg);
270 if (args_info.ipdown_arg) printf("ipdown: %s\n", args_info.ipdown_arg);
271 printf("defaultroute: %d\n", args_info.defaultroute_flag);
272 if (args_info.pinghost_arg) 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);
280 /* Handle each option */
282 /* foreground */
283 /* If fg flag not given run as a daemon */
284 /* Do not allow sgsnemu to run as deamon
285 if (!args_info.fg_flag)
287 closelog();
288 freopen("/dev/null", "w", stdout);
289 freopen("/dev/null", "w", stderr);
290 freopen("/dev/null", "r", stdin);
291 daemon(0, 0);
292 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
293 } */
295 /* debug */
296 options.debug = args_info.debug_flag;
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);
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;
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));
322 else {
323 options.dns.s_addr= 0;
324 printf("Using default DNS server\n");
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;
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));
342 else {
343 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
344 "Listening address must be specified: %s!", args_info.listen_arg);
345 return -1;
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;
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));
364 else {
365 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
366 "No remote address given!");
367 return -1;
371 /* imsi */
372 if (strlen(args_info.imsi_arg)!=15) {
373 printf("Invalid IMSI\n");
374 return -1;
377 options.imsi = 0xf000000000000000ull;
378 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 0]-48));
379 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4;
380 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8;
381 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12;
382 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16;
383 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20;
384 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24;
385 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28;
386 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32;
387 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36;
388 options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40;
389 options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44;
390 options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48;
391 options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52;
392 options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56;
394 printf("IMSI is: %s (%#08llx)\n",
395 args_info.imsi_arg, options.imsi);
398 /* nsapi */
399 if ((args_info.nsapi_arg > 15) ||
400 (args_info.nsapi_arg < 0)) {
401 printf("Invalid NSAPI\n");
402 return -1;
404 options.nsapi = args_info.nsapi_arg;
405 printf("Using NSAPI: %d\n", args_info.nsapi_arg);
408 /* qos */
409 options.qos.l = 3;
410 options.qos.v[2] = (args_info.qos_arg) & 0xff;
411 options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
412 options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
414 /* charging */
415 options.cch = args_info.charging_arg;
417 /* contexts */
418 if (args_info.contexts_arg > MAXCONTEXTS) {
419 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
420 return -1;
422 options.contexts = args_info.contexts_arg;
424 /* Timelimit */
425 options.timelimit = args_info.timelimit_arg;
427 /* gtpversion */
428 if ((args_info.gtpversion_arg > 1) ||
429 (args_info.gtpversion_arg < 0)) {
430 printf("Invalid GTP version\n");
431 return -1;
433 options.gtpversion = args_info.gtpversion_arg;
434 printf("Using GTP version: %d\n", args_info.gtpversion_arg);
437 /* apn */
438 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
439 printf("Invalid APN\n");
440 return -1;
442 options.apn.l = strlen(args_info.apn_arg);
443 strncpy((char *)options.apn.v, args_info.apn_arg, sizeof(options.apn.v));
444 options.apn.v[sizeof(options.apn.v)-1] = 0;
445 printf("Using APN: %s\n", args_info.apn_arg);
448 /* selmode */
449 options.selmode = args_info.selmode_arg;
450 printf("Using selection mode: %d\n", args_info.selmode_arg);
453 /* msisdn */
454 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
455 printf("Invalid MSISDN\n");
456 return -1;
458 options.msisdn.l = 1;
459 options.msisdn.v[0] = 0x91; /* International format */
460 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
461 if ((n%2) == 0) {
462 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
463 options.msisdn.l += 1;
465 else {
466 options.msisdn.v[((int)n/2)+1] =
467 (options.msisdn.v[((int)n/2)+1] & 0x0f) +
468 (args_info.msisdn_arg[n] - 48) * 16;
471 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
473 /* UID and PWD */
474 /* Might need to also insert stuff like DNS etc. */
475 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>
476 (sizeof(options.pco.v)-1)) {
477 printf("invalid UID and PWD\n");
478 return -1;
480 options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
481 options.pco.v[0] = 0x80; /* PPP */
482 options.pco.v[1] = 0xc0; /* PAP */
483 options.pco.v[2] = 0x23;
484 options.pco.v[3] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
485 options.pco.v[4] = 0x01; /* Authenticate request */
486 options.pco.v[5] = 0x01;
487 options.pco.v[6] = 0x00; /* MSB of length */
488 options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
489 options.pco.v[8] = strlen(args_info.uid_arg);
490 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
491 options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg);
492 memcpy(&options.pco.v[10+strlen(args_info.uid_arg)],
493 args_info.pwd_arg, strlen(args_info.pwd_arg));
495 /* createif */
496 options.createif = args_info.createif_flag;
498 /* net */
499 /* Store net as in_addr net and mask */
500 if (args_info.net_arg) {
501 if(ippool_aton(&options.net, &options.mask, args_info.net_arg, 0)) {
502 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
503 "Invalid network address: %s!", args_info.net_arg);
504 exit(1);
507 #if defined (__sun__)
508 options.netaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
509 options.destaddr.s_addr = htonl(ntohl(options.net.s_addr) + 1);
510 #else
511 options.netaddr.s_addr = options.net.s_addr;
512 options.destaddr.s_addr = options.net.s_addr;
513 #endif
516 else {
517 options.net.s_addr = 0;
518 options.mask.s_addr = 0;
519 options.netaddr.s_addr = 0;
520 options.destaddr.s_addr = 0;
523 /* ipup */
524 options.ipup = args_info.ipup_arg;
526 /* ipdown */
527 options.ipdown = args_info.ipdown_arg;
529 /* statedir */
530 options.statedir = args_info.statedir_arg;
532 /* defaultroute */
533 options.defaultroute = args_info.defaultroute_flag;
536 /* pinghost */
537 /* Store ping host as in_addr */
538 if (args_info.pinghost_arg) {
539 if (!(host = gethostbyname(args_info.pinghost_arg))) {
540 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
541 "Invalid ping host: %s!", args_info.pinghost_arg);
542 return -1;
544 else {
545 memcpy(&options.pinghost.s_addr, host->h_addr, host->h_length);
546 printf("Using ping host: %s (%s)\n",
547 args_info.pinghost_arg, inet_ntoa(options.pinghost));
551 /* Other ping parameters */
552 options.pingrate = args_info.pingrate_arg;
553 options.pingsize = args_info.pingsize_arg;
554 options.pingcount = args_info.pingcount_arg;
555 options.pingquiet = args_info.pingquiet_flag;
557 return 0;
562 int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
563 unsigned int i;
564 printf("The packet looks like this:\n");
565 for( i=0; i<len; i++) {
566 printf("%02x ", (unsigned char)*(char *)(pack+i));
567 if (!((i+1)%16)) printf("\n");
569 printf("\n");
570 return 0;
573 char * print_ipprot(int t) {
574 switch (t) {
575 case 1: return "ICMP";
576 case 6: return "TCP";
577 case 17: return "UDP";
578 default: return "Unknown";
583 char * print_icmptype(int t) {
584 static char *ttab[] = {
585 "Echo Reply",
586 "ICMP 1",
587 "ICMP 2",
588 "Dest Unreachable",
589 "Source Quench",
590 "Redirect",
591 "ICMP 6",
592 "ICMP 7",
593 "Echo",
594 "ICMP 9",
595 "ICMP 10",
596 "Time Exceeded",
597 "Parameter Problem",
598 "Timestamp",
599 "Timestamp Reply",
600 "Info Request",
601 "Info Reply"
603 if( t < 0 || t > 16 )
604 return("OUT-OF-RANGE");
605 return(ttab[t]);
608 int msisdn_add(struct ul16_t *src, struct ul16_t *dst, int add) {
609 unsigned int n;
610 uint64_t i64 = 0;
611 uint8_t msa[sizeof(i64) * 3]; /* Allocate 3 digits per octet (0..255) */
612 unsigned int msalen = 0;
614 /* Convert to uint64_t from ul16_t format (most significant digit first) */
615 /* ul16_t format always starts with 0x91 to indicate international format */
616 /* In ul16_t format 0x0f/0xf0 indicates that digit is not used */
617 for (n=0; n< src->l; n++) {
618 if ((src->v[n] & 0x0f) != 0x0f) {
619 i64 *= 10;
620 i64 += src->v[n] & 0x0f;
622 if ((src->v[n] & 0xf0) != 0xf0) {
623 i64 *= 10;
624 i64 += (src->v[n] & 0xf0) >> 4;
628 i64 += add;
630 /* Generate array with least significant digit in first octet */
631 while (i64) {
632 msa[msalen++] = i64 % 10;
633 i64 = i64 / 10;
636 /* Convert back to ul16_t format */
637 for(n=0; n<msalen; n++) {
638 if ((n%2) == 0) {
639 dst->v[((int)n/2)] = msa[msalen-n-1] + 0xf0;
640 dst->l += 1;
642 else {
643 dst->v[((int)n/2)] = (dst->v[((int)n/2)] & 0x0f) +
644 msa[msalen-n-1] * 16;
648 return 0;
652 int imsi_add(uint64_t src, uint64_t *dst, int add) {
653 /* TODO: big endian / small endian ??? */
654 uint64_t i64 = 0;
656 /* Convert from uint64_t bcd to uint64_t integer format */
657 /* The resulting integer format is multiplied by 10 */
658 while (src) {
659 if ((src & 0x0f) != 0x0f) {
660 i64 *= 10;
661 i64 += (src & 0x0f);
663 if ((src & 0xf0) != 0xf0) {
664 i64 *= 10;
665 i64 += (src & 0xf0) >> 4;
667 src = src >> 8;
670 i64 += add * 10;
672 *dst = 0;
673 while (i64) {
674 *dst = *dst << 4;
675 *dst += (i64 % 10);
676 i64 = i64 / 10;
679 *dst |= 0xf000000000000000ull;
681 return 0;
685 /* Calculate time left until we have to send off next ping packet */
686 int ping_timeout(struct timeval *tp) {
687 struct timezone tz;
688 struct timeval tv;
689 int diff;
690 if ((options.pinghost.s_addr) && (2 == state) &&
691 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
692 gettimeofday(&tv, &tz);
693 diff = 1000000 / options.pingrate * pingseq -
694 1000000 * (tv.tv_sec - firstping.tv_sec) -
695 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
696 tp->tv_sec = 0;
697 if (diff > 0)
698 tp->tv_usec = diff;
699 else {
700 /* For some reason we get packet loss if set to zero */
701 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
702 tp->tv_usec = 0;
705 return 0;
708 /* Print out statistics when at the end of ping sequence */
709 int ping_finish()
711 struct timezone tz;
712 struct timeval tv;
713 int elapsed;
714 gettimeofday(&tv, &tz);
715 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
716 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
717 printf("\n");
718 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
719 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
720 elapsed / 1000000.0);
721 printf("%d packets received, ", nreceived );
722 if (ntransmitted) {
723 if( nreceived > ntransmitted)
724 printf("-- somebody's printing up packets!");
725 else
726 printf("%d%% packet loss",
727 (int) (((ntransmitted-nreceived)*100) /
728 ntransmitted));
730 printf("\n");
731 if (options.debug) printf("%d packets received in total\n", ntreceived );
732 if (nreceived && tsum)
733 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
734 tmin/1000.0,
735 tsum/1000.0/nreceived,
736 tmax/1000.0 );
737 printf("%d packets transmitted \n", ntreceived );
739 ntransmitted = 0;
740 return 0;
743 /* Handle a received ping packet. Print out line and update statistics. */
744 int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
745 struct timezone tz;
746 struct timeval tv;
747 struct timeval *tp;
748 struct ip_ping *pingpack = pack;
749 struct in_addr src;
750 int triptime;
752 src.s_addr = pingpack->src;
754 gettimeofday(&tv, &tz);
755 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
757 if (len < CREATEPING_IP + CREATEPING_ICMP) {
758 printf("packet too short (%d bytes) from %s\n", len,
759 inet_ntoa(src));
760 return 0;
763 ntreceived++;
764 if (pingpack->protocol != 1) {
765 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
766 len, inet_ntoa(src), pingpack->protocol,
767 print_ipprot(pingpack->protocol));
768 return 0;
771 if (pingpack->type != 0) {
772 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
773 len, inet_ntoa(src), pingpack->type,
774 print_icmptype(pingpack->type), pingpack->code);
775 return 0;
778 nreceived++;
779 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
780 inet_ntoa(src), ntohs(pingpack->seq));
782 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
783 gettimeofday(&tv, &tz);
784 tp = (struct timeval *) pingpack->data;
785 if( (tv.tv_usec -= tp->tv_usec) < 0 ) {
786 tv.tv_sec--;
787 tv.tv_usec += 1000000;
789 tv.tv_sec -= tp->tv_sec;
791 triptime = tv.tv_sec*1000000+(tv.tv_usec);
792 tsum += triptime;
793 if( triptime < tmin )
794 tmin = triptime;
795 if( triptime > tmax )
796 tmax = triptime;
798 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
801 else
802 if (!options.pingquiet) printf("\n");
803 return 0;
806 /* Create a new ping packet and send it off to peer. */
807 int create_ping(void *gsn, struct pdp_t *pdp,
808 struct in_addr *dst, int seq, unsigned int datasize) {
810 struct ip_ping pack;
811 uint16_t *p = (uint16_t *) &pack;
812 uint8_t *p8 = (uint8_t *) &pack;
813 struct in_addr src;
814 unsigned int n;
815 long int sum = 0;
816 int count = 0;
818 struct timezone tz;
819 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
821 if (datasize > CREATEPING_MAX) {
822 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
823 "Ping size to large: %d!", datasize);
824 return -1;
827 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
829 pack.ipver = 0x45;
830 pack.tos = 0x00;
831 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
832 pack.fragid = 0x0000;
833 pack.offset = 0x0040;
834 pack.ttl = 0x40;
835 pack.protocol = 0x01;
836 pack.ipcheck = 0x0000;
837 pack.src = src.s_addr;
838 pack.dst = dst->s_addr;
839 pack.type = 0x08;
840 pack.code = 0x00;
841 pack.checksum = 0x0000;
842 pack.ident = 0x0000;
843 pack.seq = htons(seq);
845 /* Generate ICMP payload */
846 p8 = (uint8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
847 for (n=0; n<(datasize); n++) p8[n] = n;
849 if (datasize >= sizeof(struct timeval))
850 gettimeofday(tp, &tz);
852 /* Calculate IP header checksum */
853 p = (uint16_t *) &pack;
854 count = CREATEPING_IP;
855 sum = 0;
856 while (count>1) {
857 sum += *p++;
858 count -= 2;
860 while (sum>>16)
861 sum = (sum & 0xffff) + (sum >> 16);
862 pack.ipcheck = ~sum;
865 /* Calculate ICMP checksum */
866 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
867 sum = 0;
868 p = (uint16_t *) &pack;
869 p += CREATEPING_IP / 2;
870 while (count>1) {
871 sum += *p++;
872 count -= 2;
874 if (count>0)
875 sum += * (unsigned char *) p;
876 while (sum>>16)
877 sum = (sum & 0xffff) + (sum >> 16);
878 pack.checksum = ~sum;
880 ntransmitted++;
881 return gtp_data_req(gsn, pdp, &pack, 28 + datasize);
885 int delete_context(struct pdp_t *pdp) {
887 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
889 ipdel((struct iphash_t*) pdp->peer);
890 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
892 if (1 == options.contexts)
893 state = 5; /* Disconnected */
895 return 0;
899 /* Callback for receiving messages from tun */
900 int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
901 struct iphash_t *ipm;
902 struct in_addr src;
903 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
905 src.s_addr = iph->src;
907 if (ipget(&ipm, &src)) {
908 printf("Received packet without a valid source address!!!\n");
909 return 0;
912 if (ipm->pdp) /* Check if a peer protocol is defined */
913 gtp_data_req(gsn, ipm->pdp, pack, len);
914 return 0;
917 int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) {
918 struct in_addr addr;
920 struct iphash_t *iph = (struct iphash_t*) cbp;
922 if (cause < 0) {
923 printf("Create PDP Context Request timed out\n");
924 if (iph->pdp->version == 1) {
925 printf("Retrying with version 0\n");
926 iph->pdp->version = 0;
927 gtp_create_context_req(gsn, iph->pdp, iph);
928 return 0;
930 else {
931 state = 0;
932 pdp_freepdp(iph->pdp);
933 iph->pdp = NULL;
934 return EOF;
938 if (cause != 128) {
939 printf("Received create PDP context response. Cause value: %d\n", cause);
940 state = 0;
941 pdp_freepdp(iph->pdp);
942 iph->pdp = NULL;
943 return EOF; /* Not what we expected */
946 if (pdp_euaton(&pdp->eua, &addr)) {
947 printf("Received create PDP context response. Cause value: %d\n", cause);
948 pdp_freepdp(iph->pdp);
949 iph->pdp = NULL;
950 state = 0;
951 return EOF; /* Not a valid IP address */
954 printf("Received create PDP context response. IP address: %s\n",
955 inet_ntoa(addr));
957 if ((options.createif) && (!options.net.s_addr)) {
958 struct in_addr m;
959 #ifdef HAVE_INET_ATON
960 inet_aton("255.255.255.255", &m);
961 #else
962 m.s_addr = -1;
963 #endif
964 /* printf("Setting up interface and routing\n");*/
965 tun_addaddr(tun, &addr, &addr, &m);
966 if (options.defaultroute) {
967 struct in_addr rm;
968 rm.s_addr = 0;
969 tun_addroute(tun, &rm, &addr, &rm);
971 if (options.ipup) tun_runscript(tun, options.ipup);
974 ipset((struct iphash_t*) pdp->peer, &addr);
976 state = 2; /* Connected */
978 return 0;
981 int delete_pdp_conf(struct pdp_t *pdp, int cause) {
982 printf("Received delete PDP context response. Cause value: %d\n", cause);
983 return 0;
986 int echo_conf(int recovery) {
988 if (recovery < 0) {
989 printf("Echo Request timed out\n");
990 if (echoversion == 1) {
991 printf("Retrying with version 0\n");
992 echoversion = 0;
993 gtp_echo_req(gsn, echoversion, NULL, &options.remote);
994 return 0;
996 else {
997 state = 0;
998 return EOF;
1001 else {
1002 printf("Received echo response\n");
1003 if (!options.contexts) state = 5;
1005 return 0;
1008 int conf(int type, int cause, struct pdp_t* pdp, void *cbp) {
1009 /* if (cause < 0) return 0; Some error occurred. We don't care */
1010 switch (type) {
1011 case GTP_ECHO_REQ:
1012 return echo_conf(cause);
1013 case GTP_CREATE_PDP_REQ:
1014 return create_pdp_conf(pdp, cbp, cause);
1015 case GTP_DELETE_PDP_REQ:
1016 if (cause !=128) return 0; /* Request not accepted. We don't care */
1017 return delete_pdp_conf(pdp, cause);
1018 default:
1019 return 0;
1024 int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
1025 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
1026 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
1029 int main(int argc, char **argv)
1031 fd_set fds; /* For select() */
1032 struct timeval idleTime; /* How long to select() */
1033 struct pdp_t *pdp;
1034 int n;
1035 int starttime = time(NULL); /* Time program was started */
1036 int stoptime = 0; /* Time to exit */
1037 int pingtimeout = 0; /* Time to print ping statistics */
1039 struct timezone tz; /* Used for calculating ping times */
1040 struct timeval tv;
1041 int diff;
1043 /* open a connection to the syslog daemon */
1044 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
1045 /* TODO: Only use LOG__PERROR for linux */
1047 #ifdef __linux__
1048 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
1049 #else
1050 openlog(PACKAGE, (LOG_PID), LOG_DAEMON);
1051 #endif
1054 /* Process options given in configuration file and command line */
1055 if (process_options(argc, argv))
1056 exit(1);
1058 printf("\nInitialising GTP library\n");
1059 if (gtp_new(&gsn, options.statedir, &options.listen, GTP_MODE_SGSN)) {
1060 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1061 "Failed to create gtp");
1062 exit(1);
1064 if (gsn->fd0 > maxfd) maxfd = gsn->fd0;
1065 if (gsn->fd1c > maxfd) maxfd = gsn->fd1c;
1066 if (gsn->fd1u > maxfd) maxfd = gsn->fd1u;
1068 gtp_set_cb_delete_context(gsn, delete_context);
1069 gtp_set_cb_conf(gsn, conf);
1070 if (options.createif)
1071 gtp_set_cb_data_ind(gsn, encaps_tun);
1072 else
1073 gtp_set_cb_data_ind(gsn, encaps_ping);
1075 if (options.createif) {
1076 printf("Setting up interface\n");
1077 /* Create a tunnel interface */
1078 if (tun_new((struct tun_t**) &tun)) {
1079 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1080 "Failed to create tun");
1081 exit(1);
1083 tun_set_cb_ind(tun, cb_tun_ind);
1084 if (tun->fd > maxfd) maxfd = tun->fd;
1087 if ((options.createif) && (options.net.s_addr)) {
1088 /* printf("Setting up interface and routing\n");*/
1089 tun_addaddr(tun, &options.netaddr, &options.destaddr, &options.mask);
1090 if (options.defaultroute) {
1091 struct in_addr rm;
1092 rm.s_addr = 0;
1093 tun_addroute(tun, &rm, &options.destaddr, &rm);
1095 if (options.ipup) tun_runscript(tun, options.ipup);
1099 /* Initialise hash tables */
1100 memset(&iphash, 0, sizeof(iphash));
1101 memset(&iparr, 0, sizeof(iparr));
1103 printf("Done initialising GTP library\n\n");
1105 /* See if anybody is there */
1106 printf("Sending off echo request\n");
1107 echoversion = options.gtpversion;
1108 gtp_echo_req(gsn, echoversion, NULL, &options.remote); /* Is remote alive? */
1110 for(n=0; n<options.contexts; n++) {
1111 uint64_t myimsi;
1112 printf("Setting up PDP context #%d\n", n);
1113 iparr[n].inuse = 1; /* TODO */
1115 imsi_add(options.imsi, &myimsi, n);
1117 /* Allocated here. */
1118 /* If create context failes we have to deallocate ourselves. */
1119 /* Otherwise it is deallocated by gtplib */
1120 pdp_newpdp(&pdp, myimsi, options.nsapi, NULL);
1122 pdp->peer = &iparr[n];
1123 pdp->ipif = tun; /* TODO */
1124 iparr[n].pdp = pdp;
1126 if (options.qos.l > sizeof(pdp->qos_req0)) {
1127 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
1128 exit(1);
1130 else {
1131 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
1134 /* TODO */
1135 pdp->qos_req.l = 4;
1136 pdp->qos_req.v[0] = 0x00;
1137 memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l);
1139 pdp->selmode = options.selmode;
1141 if (options.apn.l > sizeof(pdp->apn_use.v)) {
1142 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
1143 exit(1);
1145 else {
1146 pdp->apn_use.l = options.apn.l;
1147 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
1150 pdp->gsnlc.l = sizeof(options.listen);
1151 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
1152 pdp->gsnlu.l = sizeof(options.listen);
1153 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
1155 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
1156 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
1157 exit(1);
1159 else {
1160 msisdn_add(&options.msisdn, &pdp->msisdn, n);
1163 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
1165 if (options.pco.l > sizeof(pdp->pco_req.v)) {
1166 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
1167 exit(1);
1169 else {
1170 pdp->pco_req.l = options.pco.l;
1171 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
1174 pdp->version = options.gtpversion;
1176 pdp->hisaddr0 = options.remote;
1177 pdp->hisaddr1 = options.remote;
1179 pdp->cch_pdp = options.cch; /* 2048 = Normal, 1024 = Prepaid,
1180 512 = Flat rate, 256 = Hot billing */
1182 /* Create context */
1183 /* We send this of once. Retransmissions are handled by gtplib */
1184 gtp_create_context_req(gsn, pdp, &iparr[n]);
1187 state = 1; /* Enter wait_connection state */
1189 printf("Waiting for response from ggsn........\n\n");
1192 /******************************************************************/
1193 /* Main select loop */
1194 /******************************************************************/
1196 while ((0 != state) && (5 != state)) {
1198 /* Take down client after timeout after disconnect */
1199 if ((4 == state) && ((stoptime) <= time(NULL))) {
1200 state = 5;
1203 /* Take down client after timelimit timeout */
1204 if ((2 == state) && (options.timelimit) &&
1205 ((starttime + options.timelimit) <= time(NULL))) {
1206 state = 3;
1209 /* Take down client after ping timeout */
1210 if ((2 == state) && (pingtimeout) && (pingtimeout <= time(NULL))) {
1211 state = 3;
1214 /* Set pingtimeout for later disconnection */
1215 if (options.pingcount && ntransmitted >= options.pingcount) {
1216 pingtimeout = time(NULL) + 5; /* Extra seconds */
1219 /* Print statistics if no more ping packets are missing */
1220 if (ntransmitted && options.pingcount && nreceived >= options.pingcount) {
1221 ping_finish();
1222 if (!options.createif)
1223 state = 3;
1226 /* Send off disconnect */
1227 if (3 == state) {
1228 state = 4;
1229 stoptime = time(NULL) + 5; /* Extra seconds to allow disconnect */
1230 for(n=0; n<options.contexts; n++) {
1231 /* Delete context */
1232 printf("Disconnecting PDP context #%d\n", n);
1233 gtp_delete_context_req(gsn, iparr[n].pdp, NULL, 1);
1234 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
1238 /* Send of ping packets */
1239 diff = 0;
1240 while (( diff<=0 ) &&
1241 /* Send off an ICMP ping packet */
1242 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
1243 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
1244 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
1245 gettimeofday(&tv, &tz);
1246 diff = 1000000 / options.pingrate * pingseq -
1247 1000000 * (tv.tv_sec - firstping.tv_sec) -
1248 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1249 if (diff <=0) {
1250 if (options.debug) printf("Create_ping %d\n", diff);
1251 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1252 &options.pinghost, pingseq, options.pingsize);
1253 pingseq++;
1257 FD_ZERO(&fds);
1258 if (tun) FD_SET(tun->fd, &fds);
1259 FD_SET(gsn->fd0, &fds);
1260 FD_SET(gsn->fd1c, &fds);
1261 FD_SET(gsn->fd1u, &fds);
1263 gtp_retranstimeout(gsn, &idleTime);
1264 ping_timeout(&idleTime);
1266 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1267 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1269 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1270 case -1:
1271 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1272 "Select returned -1");
1273 break;
1274 case 0:
1275 gtp_retrans(gsn); /* Only retransmit if nothing else */
1276 break;
1277 default:
1278 break;
1281 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1282 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1283 "TUN decaps failed");
1286 if (FD_ISSET(gsn->fd0, &fds))
1287 gtp_decaps0(gsn);
1289 if (FD_ISSET(gsn->fd1c, &fds))
1290 gtp_decaps1c(gsn);
1292 if (FD_ISSET(gsn->fd1u, &fds))
1293 gtp_decaps1u(gsn);
1296 gtp_free(gsn); /* Clean up the gsn instance */
1298 if (options.createif)
1299 tun_free(tun);
1301 if (0 == state)
1302 exit(1); /* Indicate error */
1304 return 0;