blob: 99f036619b6b74ca9dbb1c0379fe5fa643406e53 [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 */
78/* 3: Wait_disconnect */
jjako52c24142002-12-16 13:33:51 +000079int state = 0;
80
jjakoa7cd2492003-04-11 09:40:12 +000081struct gsn_t *gsn = NULL; /* GSN instance */
82struct tun_t *tun = NULL; /* TUN instance */
jjako52c24142002-12-16 13:33:51 +000083int maxfd = 0; /* For select() */
jjako52c24142002-12-16 13:33:51 +000084
jjakoa7cd2492003-04-11 09:40:12 +000085/* Struct with local versions of gengetopt options */
86struct {
87 int debug; /* Print debug messages */
88 int createif; /* Create local network interface */
89 char *ipup, *ipdown; /* Filename of scripts */
90 int defaultroute; /* Set up default route */
91 struct in_addr pinghost; /* Remote ping host */
92 int pingrate;
93 int pingsize;
94 int pingcount;
95 int pingquiet;
96 struct in_addr listen;
97 struct in_addr remote;
98 struct in_addr dns;
99 int contexts; /* Number of contexts to create */
100 int timelimit; /* Number of seconds to be connected */
101 char *statedir;
102 uint64_t imsi;
103 struct ul255_t pco;
104 struct ul255_t qos;
105 struct ul255_t apn;
106 struct ul16_t msisdn;
107} options;
jjako52c24142002-12-16 13:33:51 +0000108
jjako5da68452003-01-28 16:08:47 +0000109
110/* Definitions to use for PING. Most of the ping code was derived from */
111/* the original ping program by Mike Muuss */
112
113/* IP header and ICMP echo header */
114#define CREATEPING_MAX 2048
115#define CREATEPING_IP 20
116#define CREATEPING_ICMP 8
117
118struct ip_ping {
119 u_int8_t ipver; /* Type and header length*/
120 u_int8_t tos; /* Type of Service */
121 u_int16_t length; /* Total length */
122 u_int16_t fragid; /* Identifier */
123 u_int16_t offset; /* Flags and fragment offset */
124 u_int8_t ttl; /* Time to live */
125 u_int8_t protocol; /* Protocol */
126 u_int16_t ipcheck; /* Header checksum */
127 u_int32_t src; /* Source address */
128 u_int32_t dst; /* Destination */
129 u_int8_t type; /* Type and header length*/
130 u_int8_t code; /* Code */
131 u_int16_t checksum; /* Header checksum */
132 u_int16_t ident; /* Identifier */
133 u_int16_t seq; /* Sequence number */
134 u_int8_t data[CREATEPING_MAX]; /* Data */
135} __attribute__((packed));
136
137/* Statistical values for ping */
138int nreceived = 0;
139int ntreceived = 0;
140int ntransmitted = 0;
141int tmin = 999999999;
142int tmax = 0;
143int tsum = 0;
jjakoafb2a972003-01-29 21:04:13 +0000144int pingseq = 0; /* Ping sequence counter */
145struct timeval firstping;
jjako5da68452003-01-28 16:08:47 +0000146
jjakoa7cd2492003-04-11 09:40:12 +0000147int ipset(struct iphash_t *ipaddr, struct in_addr *addr) {
148 int hash = ippool_hash4(addr) % MAXCONTEXTS;
149 struct iphash_t *h;
150 struct iphash_t *prev = NULL;
151 ipaddr->ipnext = NULL;
152 ipaddr->addr.s_addr = addr->s_addr;
153 for (h = iphash[hash]; h; h = h->ipnext)
154 prev = h;
155 if (!prev)
156 iphash[hash] = ipaddr;
157 else
158 prev->ipnext = ipaddr;
159 return 0;
160}
161
162int ipdel(struct iphash_t *ipaddr) {
163 int hash = ippool_hash4(&ipaddr->addr) % MAXCONTEXTS;
164 struct iphash_t *h;
165 struct iphash_t *prev = NULL;
166 for (h = iphash[hash]; h; h = h->ipnext) {
167 if (h == ipaddr) {
168 if (!prev)
169 iphash[hash] = h->ipnext;
170 else
171 prev->ipnext = h->ipnext;
172 return 0;
173 }
174 prev = h;
175 }
176 return EOF; /* End of linked list and not found */
177}
178
179int ipget(struct iphash_t **ipaddr, struct in_addr *addr) {
180 int hash = ippool_hash4(addr) % MAXCONTEXTS;
181 struct iphash_t *h;
182 for (h = iphash[hash]; h; h = h->ipnext) {
183 if ((h->addr.s_addr == addr->s_addr)) {
184 *ipaddr = h;
185 return 0;
186 }
187 }
188 return EOF; /* End of linked list and not found */
189}
190
191
192/* Used to write process ID to file. Assume someone else will delete */
193void log_pid(char *pidfile) {
194 FILE *file;
195 mode_t oldmask;
196
197 oldmask = umask(022);
198 file = fopen(pidfile, "w");
199 umask(oldmask);
200 if(!file)
201 return;
202 fprintf(file, "%d\n", getpid());
203 fclose(file);
204}
205
206
207int process_options(int argc, char **argv) {
208 /* gengeopt declarations */
209 struct gengetopt_args_info args_info;
210
211 struct hostent *host;
212 int n;
213
214 if (cmdline_parser (argc, argv, &args_info) != 0)
215 return -1;
216 if (args_info.debug_flag) {
217 printf("remote: %s\n", args_info.remote_arg);
218 printf("listen: %s\n", args_info.listen_arg);
219 printf("conf: %s\n", args_info.conf_arg);
220 printf("fg: %d\n", args_info.fg_flag);
221 printf("debug: %d\n", args_info.debug_flag);
222 printf("imsi: %s\n", args_info.imsi_arg);
223 printf("qos: %#08x\n", args_info.qos_arg);
224 printf("apn: %s\n", args_info.apn_arg);
225 printf("msisdn: %s\n", args_info.msisdn_arg);
226 printf("uid: %s\n", args_info.uid_arg);
227 printf("pwd: %s\n", args_info.pwd_arg);
228 printf("pidfile: %s\n", args_info.pidfile_arg);
229 printf("statedir: %s\n", args_info.statedir_arg);
230 printf("dns: %s\n", args_info.dns_arg);
231 printf("contexts: %d\n", args_info.contexts_arg);
232 printf("timelimit: %d\n", args_info.timelimit_arg);
233 printf("createif: %d\n", args_info.createif_flag);
234 printf("ipup: %s\n", args_info.ipup_arg);
235 printf("ipdown: %s\n", args_info.ipdown_arg);
236 printf("defaultroute: %d\n", args_info.defaultroute_flag);
237 printf("pinghost: %s\n", args_info.pinghost_arg);
238 printf("pingrate: %d\n", args_info.pingrate_arg);
239 printf("pingsize: %d\n", args_info.pingsize_arg);
240 printf("pingcount: %d\n", args_info.pingcount_arg);
241 printf("pingquiet: %d\n", args_info.pingquiet_flag);
242 }
243
244 /* Try out our new parser */
245
246 if (args_info.conf_arg) {
247 if (cmdline_parser_configfile (args_info.conf_arg, &args_info, 0) != 0)
248 return -1;
249 if (args_info.debug_flag) {
250 printf("cmdline_parser_configfile\n");
251 printf("remote: %s\n", args_info.remote_arg);
252 printf("listen: %s\n", args_info.listen_arg);
253 printf("conf: %s\n", args_info.conf_arg);
254 printf("fg: %d\n", args_info.fg_flag);
255 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 */
282 /* If fg flag not given run as a daemon */
283 if (!args_info.fg_flag)
284 {
285 closelog();
286 /* Close the standard file descriptors. Why? */
287 freopen("/dev/null", "w", stdout);
288 freopen("/dev/null", "w", stderr);
289 freopen("/dev/null", "r", stdin);
290 daemon(0, 0);
291 /* Open log again. This time with new pid */
292 openlog(PACKAGE, LOG_PID, LOG_DAEMON);
293 }
294
295 /* debug */
296 options.debug = args_info.debug_flag;
297
298 /* pidfile */
299 /* This has to be done after we have our final pid */
300 if (args_info.pidfile_arg) {
301 log_pid(args_info.pidfile_arg);
302 }
303
304 /* dns */
305 /* If no dns option is given use system default */
306 /* Do hostname lookup to translate hostname to IP address */
307 printf("\n");
308 if (args_info.dns_arg) {
309 if (!(host = gethostbyname(args_info.dns_arg))) {
310 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
311 "Invalid DNS address: %s!", args_info.dns_arg);
312 return -1;
313 }
314 else {
315 memcpy(&options.dns.s_addr, host->h_addr, host->h_length);
316 _res.nscount = 1;
317 _res.nsaddr_list[0].sin_addr = options.dns;
318 printf("Using DNS server: %s (%s)\n",
319 args_info.dns_arg, inet_ntoa(options.dns));
320 }
321 }
322 else {
323 options.dns.s_addr= 0;
324 printf("Using default DNS server\n");
325 }
326
327 /* listen */
328 /* If no listen option is specified listen to any local port */
329 /* Do hostname lookup to translate hostname to IP address */
330 if (args_info.listen_arg) {
331 if (!(host = gethostbyname(args_info.listen_arg))) {
332 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
333 "Invalid listening address: %s!", args_info.listen_arg);
334 return -1;
335 }
336 else {
337 memcpy(&options.listen.s_addr, host->h_addr, host->h_length);
338 printf("Local IP address is: %s (%s)\n",
339 args_info.listen_arg, inet_ntoa(options.listen));
340 }
341 }
342 else {
343 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
344 "Listening address must be specified: %s!", args_info.listen_arg);
345 return -1;
346 }
347
348
349 /* remote */
350 /* If no remote option is specified terminate */
351 /* Do hostname lookup to translate hostname to IP address */
352 if (args_info.remote_arg) {
353 if (!(host = gethostbyname(args_info.remote_arg))) {
354 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
355 "Invalid remote address: %s!", args_info.remote_arg);
356 return -1;
357 }
358 else {
359 memcpy(&options.remote.s_addr, host->h_addr, host->h_length);
360 printf("Remote IP address is: %s (%s)\n",
361 args_info.remote_arg, inet_ntoa(options.remote));
362 }
363 }
364 else {
365 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
366 "No remote address given!");
367 return -1;
368 }
369
370
371 /* imsi */
372 if (strlen(args_info.imsi_arg)!=15) {
373 printf("Invalid IMSI\n");
374 return -1;
375 }
376 options.imsi = ((uint64_t) (args_info.imsi_arg[ 0]-48));
377 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 1]-48)) << 4;
378 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 2]-48)) << 8;
379 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 3]-48)) << 12;
380 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 4]-48)) << 16;
381 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 5]-48)) << 20;
382 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 6]-48)) << 24;
383 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 7]-48)) << 28;
384 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 8]-48)) << 32;
385 options.imsi |= ((uint64_t) (args_info.imsi_arg[ 9]-48)) << 36;
386 options.imsi |= ((uint64_t) (args_info.imsi_arg[10]-48)) << 40;
387 options.imsi |= ((uint64_t) (args_info.imsi_arg[11]-48)) << 44;
388 options.imsi |= ((uint64_t) (args_info.imsi_arg[12]-48)) << 48;
389 options.imsi |= ((uint64_t) (args_info.imsi_arg[13]-48)) << 52;
390 options.imsi |= ((uint64_t) (args_info.imsi_arg[14]-48)) << 56;
391
392 printf("IMSI is: %s (%#08llx)\n",
393 args_info.imsi_arg, options.imsi);
394
395
396 /* qos */
397 options.qos.l = 3;
398 options.qos.v[2] = (args_info.qos_arg) & 0xff;
399 options.qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
400 options.qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
401
402 /* contexts */
403 if (args_info.contexts_arg > MAXCONTEXTS) {
404 printf("Contexts has to be less than %d\n", MAXCONTEXTS);
405 return -1;
406 }
407 options.contexts = args_info.contexts_arg;
408
409 /* Timelimit */
410 options.timelimit = args_info.timelimit_arg;
411
412 /* apn */
413 if (strlen(args_info.apn_arg) > (sizeof(options.apn.v)-1)) {
414 printf("Invalid APN\n");
415 return -1;
416 }
417 options.apn.l = strlen(args_info.apn_arg) + 1;
418 options.apn.v[0] = (char) strlen(args_info.apn_arg);
419 strncpy(&options.apn.v[1], args_info.apn_arg, sizeof(options.apn.v)-1);
420 printf("Using APN: %s\n", args_info.apn_arg);
421
422 /* msisdn */
423 if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
424 printf("Invalid MSISDN\n");
425 return -1;
426 }
427 options.msisdn.l = 1;
428 options.msisdn.v[0] = 0x91; /* International format */
429 for(n=0; n<strlen(args_info.msisdn_arg); n++) {
430 if ((n%2) == 0) {
431 options.msisdn.v[((int)n/2)+1] = args_info.msisdn_arg[n] - 48 + 0xf0;
432 options.msisdn.l += 1;
433 }
434 else {
435 options.msisdn.v[((int)n/2)+1] =
436 (options.msisdn.v[((int)n/2)+1] & 0x0f) +
437 (args_info.msisdn_arg[n] - 48) * 16;
438 }
439 }
440 printf("Using MSISDN: %s\n", args_info.msisdn_arg);
441
442 /* UID and PWD */
443 /* Might need to also insert stuff like DNS etc. */
444 if ((strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10)>
445 (sizeof(options.pco.v)-1)) {
446 printf("invalid UID and PWD\n");
447 return -1;
448 }
449 options.pco.l = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 10;
450 options.pco.v[0] = 0x80; /* PPP */
451 options.pco.v[1] = 0xc0; /* PAP */
452 options.pco.v[2] = 0x23;
453 options.pco.v[3] = 0x12; /* Length of protocol contents */
454 options.pco.v[4] = 0x01; /* Authenticate request */
455 options.pco.v[5] = 0x01;
456 options.pco.v[6] = 0x00; /* MSB of length */
457 options.pco.v[7] = strlen(args_info.uid_arg) + strlen(args_info.pwd_arg) + 6;
458 options.pco.v[8] = strlen(args_info.uid_arg);
459 memcpy(&options.pco.v[9], args_info.uid_arg, strlen(args_info.uid_arg));
460 options.pco.v[9+strlen(args_info.uid_arg)] = strlen(args_info.pwd_arg);
461 memcpy(&options.pco.v[10+strlen(args_info.uid_arg)],
462 args_info.pwd_arg, strlen(args_info.pwd_arg));
463
464 /* createif */
465 options.createif = args_info.createif_flag;
466
467 /* ipup */
468 options.ipup = args_info.ipup_arg;
469
470 /* ipdown */
471 options.ipdown = args_info.ipdown_arg;
472
473 /* statedir */
474 options.statedir = args_info.statedir_arg;
475
476 /* defaultroute */
477 options.defaultroute = args_info.defaultroute_flag;
478
479
480 /* pinghost */
481 /* Store ping host as in_addr */
482 if (args_info.pinghost_arg) {
483 if (!inet_aton(args_info.pinghost_arg, &options.pinghost)) {
484 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
485 "Invalid ping host: %s!", args_info.pinghost_arg);
486 return -1;
487 }
488 }
489
490 /* Other ping parameters */
491 options.pingrate = args_info.pingrate_arg;
492 options.pingsize = args_info.pingsize_arg;
493 options.pingcount = args_info.pingcount_arg;
494 options.pingquiet = args_info.pingquiet_flag;
495
496 return 0;
497
498}
499
jjako5da68452003-01-28 16:08:47 +0000500
501int encaps_printf(struct pdp_t *pdp, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000502 int i;
503 printf("The packet looks like this:\n");
504 for( i=0; i<len; i++) {
jjako5da68452003-01-28 16:08:47 +0000505 printf("%02x ", (unsigned char)*(char *)(pack+i));
jjako52c24142002-12-16 13:33:51 +0000506 if (!((i+1)%16)) printf("\n");
507 };
jjako5da68452003-01-28 16:08:47 +0000508 printf("\n");
509 return 0;
jjako52c24142002-12-16 13:33:51 +0000510}
511
jjako5da68452003-01-28 16:08:47 +0000512char * print_ipprot(int t) {
513 switch (t) {
514 case 1: return "ICMP";
515 case 6: return "TCP";
516 case 17: return "UDP";
517 default: return "Unknown";
518 };
519}
520
521
522char * print_icmptype(int t) {
523 static char *ttab[] = {
524 "Echo Reply",
525 "ICMP 1",
526 "ICMP 2",
527 "Dest Unreachable",
528 "Source Quench",
529 "Redirect",
530 "ICMP 6",
531 "ICMP 7",
532 "Echo",
533 "ICMP 9",
534 "ICMP 10",
535 "Time Exceeded",
536 "Parameter Problem",
537 "Timestamp",
538 "Timestamp Reply",
539 "Info Request",
540 "Info Reply"
541 };
542 if( t < 0 || t > 16 )
543 return("OUT-OF-RANGE");
544 return(ttab[t]);
545}
546
jjakoafb2a972003-01-29 21:04:13 +0000547/* Calculate time left until we have to send off next ping packet */
548int ping_timeout(struct timeval *tp) {
549 struct timezone tz;
550 struct timeval tv;
551 int diff;
jjakoa7cd2492003-04-11 09:40:12 +0000552 if ((options.pinghost.s_addr) && (2 == state) &&
553 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000554 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000555 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000556 1000000 * (tv.tv_sec - firstping.tv_sec) -
557 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
558 tp->tv_sec = 0;
559 if (diff > 0)
560 tp->tv_usec = diff;
jjakoa7cd2492003-04-11 09:40:12 +0000561 else {
jjakoafb2a972003-01-29 21:04:13 +0000562 /* For some reason we get packet loss if set to zero */
jjakoa7cd2492003-04-11 09:40:12 +0000563 tp->tv_usec = 100000 / options.pingrate; /* 10 times pingrate */
564 tp->tv_usec = 0;
565 }
jjakoafb2a972003-01-29 21:04:13 +0000566 }
567 return 0;
568}
569
jjako5da68452003-01-28 16:08:47 +0000570/* Print out statistics when at the end of ping sequence */
571int ping_finish()
572{
jjakoafb2a972003-01-29 21:04:13 +0000573 struct timezone tz;
574 struct timeval tv;
575 int elapsed;
576 gettimeofday(&tv, &tz);
577 elapsed = 1000000 * (tv.tv_sec - firstping.tv_sec) +
578 (tv.tv_usec - firstping.tv_usec); /* Microseconds */
jjako5da68452003-01-28 16:08:47 +0000579 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000580 printf("\n----%s PING Statistics----\n", inet_ntoa(options.pinghost));
jjakoafb2a972003-01-29 21:04:13 +0000581 printf("%d packets transmitted in %.3f seconds, ", ntransmitted,
582 elapsed / 1000000.0);
jjako5da68452003-01-28 16:08:47 +0000583 printf("%d packets received, ", nreceived );
584 if (ntransmitted) {
585 if( nreceived > ntransmitted)
586 printf("-- somebody's printing up packets!");
587 else
588 printf("%d%% packet loss",
589 (int) (((ntransmitted-nreceived)*100) /
590 ntransmitted));
591 }
592 printf("\n");
jjakoa7cd2492003-04-11 09:40:12 +0000593 if (options.debug) printf("%d packets received in total\n", ntreceived );
jjako5da68452003-01-28 16:08:47 +0000594 if (nreceived && tsum)
595 printf("round-trip (ms) min/avg/max = %.3f/%.3f/%.3f\n\n",
596 tmin/1000.0,
597 tsum/1000.0/nreceived,
598 tmax/1000.0 );
jjakoafb2a972003-01-29 21:04:13 +0000599 printf("%d packets transmitted \n", ntreceived );
600
jjako5da68452003-01-28 16:08:47 +0000601 ntransmitted = 0;
602 return 0;
603}
604
605/* Handle a received ping packet. Print out line and update statistics. */
606int encaps_ping(struct pdp_t *pdp, void *pack, unsigned len) {
607 struct timezone tz;
608 struct timeval tv;
609 struct timeval *tp;
610 struct ip_ping *pingpack = pack;
611 struct in_addr src;
612 int triptime;
613
614 src.s_addr = pingpack->src;
615
616 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000617 if (options.debug) printf("%d.%6d ", (int) tv.tv_sec, (int) tv.tv_usec);
jjako5da68452003-01-28 16:08:47 +0000618
619 if (len < CREATEPING_IP + CREATEPING_ICMP) {
620 printf("packet too short (%d bytes) from %s\n", len,
621 inet_ntoa(src));
622 return 0;
623 }
624
625 ntreceived++;
626 if (pingpack->protocol != 1) {
jjakoa7cd2492003-04-11 09:40:12 +0000627 if (!options.pingquiet) printf("%d bytes from %s: ip_protocol=%d (%s)\n",
jjako5da68452003-01-28 16:08:47 +0000628 len, inet_ntoa(src), pingpack->protocol,
629 print_ipprot(pingpack->protocol));
630 return 0;
631 }
632
633 if (pingpack->type != 0) {
jjakoa7cd2492003-04-11 09:40:12 +0000634 if (!options.pingquiet) printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n",
jjako5da68452003-01-28 16:08:47 +0000635 len, inet_ntoa(src), pingpack->type,
636 print_icmptype(pingpack->type), pingpack->code);
637 return 0;
638 }
639
640 nreceived++;
jjakoa7cd2492003-04-11 09:40:12 +0000641 if (!options.pingquiet) printf("%d bytes from %s: icmp_seq=%d", len,
jjako5da68452003-01-28 16:08:47 +0000642 inet_ntoa(src), ntohs(pingpack->seq));
643
644 if (len >= sizeof(struct timeval) + CREATEPING_IP + CREATEPING_ICMP) {
645 gettimeofday(&tv, &tz);
646 tp = (struct timeval *) pingpack->data;
647 if( (tv.tv_usec -= tp->tv_usec) < 0 ) {
648 tv.tv_sec--;
649 tv.tv_usec += 1000000;
650 }
651 tv.tv_sec -= tp->tv_sec;
652
653 triptime = tv.tv_sec*1000000+(tv.tv_usec);
654 tsum += triptime;
655 if( triptime < tmin )
656 tmin = triptime;
657 if( triptime > tmax )
658 tmax = triptime;
659
jjakoa7cd2492003-04-11 09:40:12 +0000660 if (!options.pingquiet) printf(" time=%.3f ms\n", triptime/1000.0);
jjako5da68452003-01-28 16:08:47 +0000661
662 }
663 else
jjakoa7cd2492003-04-11 09:40:12 +0000664 if (!options.pingquiet) printf("\n");
jjako5da68452003-01-28 16:08:47 +0000665 return 0;
666}
667
668/* Create a new ping packet and send it off to peer. */
669int create_ping(void *gsn, struct pdp_t *pdp,
670 struct in_addr *dst, int seq, int datasize) {
671
672 struct ip_ping pack;
673 u_int16_t *p = (u_int16_t *) &pack;
674 u_int8_t *p8 = (u_int8_t *) &pack;
675 struct in_addr src;
676 int n;
677 long int sum = 0;
678 int count = 0;
679
680 struct timezone tz;
681 struct timeval *tp = (struct timeval *) &p8[CREATEPING_IP + CREATEPING_ICMP];
682
683 if (datasize > CREATEPING_MAX) {
jjakoa7cd2492003-04-11 09:40:12 +0000684 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
685 "Ping size to large: %d!", datasize);
686 return -1;
jjako5da68452003-01-28 16:08:47 +0000687 }
688
689 memcpy(&src, &(pdp->eua.v[2]), 4); /* Copy a 4 byte address */
690
691 pack.ipver = 0x45;
692 pack.tos = 0x00;
693 pack.length = htons(CREATEPING_IP + CREATEPING_ICMP + datasize);
694 pack.fragid = 0x0000;
695 pack.offset = 0x0040;
696 pack.ttl = 0x40;
697 pack.protocol = 0x01;
698 pack.ipcheck = 0x0000;
699 pack.src = src.s_addr;
700 pack.dst = dst->s_addr;
701 pack.type = 0x08;
702 pack.code = 0x00;
703 pack.checksum = 0x0000;
704 pack.ident = 0x0000;
705 pack.seq = htons(seq);
706
707 /* Generate ICMP payload */
708 p8 = (u_int8_t *) &pack + CREATEPING_IP + CREATEPING_ICMP;
709 for (n=0; n<(datasize); n++) p8[n] = n;
710
711 if (datasize >= sizeof(struct timeval))
712 gettimeofday(tp, &tz);
713
714 /* Calculate IP header checksum */
715 p = (u_int16_t *) &pack;
716 count = CREATEPING_IP;
717 sum = 0;
718 while (count>1) {
719 sum += *p++;
720 count -= 2;
721 }
722 while (sum>>16)
723 sum = (sum & 0xffff) + (sum >> 16);
724 pack.ipcheck = ~sum;
725
726
727 /* Calculate ICMP checksum */
728 count = CREATEPING_ICMP + datasize; /* Length of ICMP message */
729 sum = 0;
730 p = (u_int16_t *) &pack;
731 p += CREATEPING_IP / 2;
732 while (count>1) {
733 sum += *p++;
734 count -= 2;
735 }
736 if (count>0)
737 sum += * (unsigned char *) p;
738 while (sum>>16)
739 sum = (sum & 0xffff) + (sum >> 16);
740 pack.checksum = ~sum;
741
742 ntransmitted++;
jjako5da68452003-01-28 16:08:47 +0000743 return gtp_gpdu(gsn, pdp, &pack, 28 + datasize);
744}
745
746
jjakoa7cd2492003-04-11 09:40:12 +0000747int delete_context(struct pdp_t *pdp) {
748
749 if (tun && options.ipdown) tun_runscript(tun, options.ipdown);
750
751 ipdel((struct iphash_t*) pdp->peer);
752 memset(pdp->peer, 0, sizeof(struct iphash_t)); /* To be sure */
753 return 0;
jjako52c24142002-12-16 13:33:51 +0000754}
755
jjakoa7cd2492003-04-11 09:40:12 +0000756
757/* Callback for receiving messages from tun */
758int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
759 struct iphash_t *ipm;
760 struct in_addr src;
761 struct tun_packet_t *iph = (struct tun_packet_t*) pack;
762
763 src.s_addr = iph->src;
764
765 if (ipget(&ipm, &src)) {
766 printf("Received packet without a valid source address!!!\n");
767 return 0;
jjako52c24142002-12-16 13:33:51 +0000768 }
jjako5da68452003-01-28 16:08:47 +0000769
jjakoa7cd2492003-04-11 09:40:12 +0000770 if (ipm->pdp) /* Check if a peer protocol is defined */
771 gtp_gpdu(gsn, ipm->pdp, pack, len);
jjako52c24142002-12-16 13:33:51 +0000772 return 0;
773}
774
775int create_pdp_conf(struct pdp_t *pdp, int cause) {
jjakoa7cd2492003-04-11 09:40:12 +0000776 struct in_addr addr;
jjako52c24142002-12-16 13:33:51 +0000777
jjakoa7cd2492003-04-11 09:40:12 +0000778 if (cause != 128) {
779 printf("Received create PDP context response. Cause value: %d\n", cause);
jjako52c24142002-12-16 13:33:51 +0000780 state = 0;
jjakoa7cd2492003-04-11 09:40:12 +0000781 return EOF; /* Not what we expected */
jjako52c24142002-12-16 13:33:51 +0000782 }
783
jjakoa7cd2492003-04-11 09:40:12 +0000784 if (pdp_euaton(&pdp->eua, &addr)) {
785 printf("Received create PDP context response. Cause value: %d\n", cause);
786 state = 0;
787 return EOF; /* Not a valid IP address */
788 }
789
790 printf("Received create PDP context response. IP address: %s\n",
791 inet_ntoa(addr));
792
793 if (options.createif) {
794 struct in_addr m;
795 inet_aton("255.255.255.255", &m);
796 /* printf("Setting up interface and routing\n");*/
797 tun_addaddr(tun, &addr, &addr, &m);
798 if (options.defaultroute) {
799 struct in_addr rm;
800 rm.s_addr = 0;
801 tun_addroute(tun, &rm, &addr, &rm);
802 }
803 if (options.ipup) tun_runscript(tun, options.ipup);
804 }
805
806 ipset((struct iphash_t*) pdp->peer, &addr);
807
808 state = 2; /* Connected */
jjako52c24142002-12-16 13:33:51 +0000809
810 return 0;
811}
812
jjako52c24142002-12-16 13:33:51 +0000813int delete_pdp_conf(struct pdp_t *pdp, int cause) {
814 printf("Received delete PDP context response. Cause value: %d\n", cause);
jjako5da68452003-01-28 16:08:47 +0000815 state = 0; /* Idle */
jjako52c24142002-12-16 13:33:51 +0000816 return 0;
817}
818
819int echo_conf(struct pdp_t *pdp, int cause) {
jjako5da68452003-01-28 16:08:47 +0000820 if (cause <0)
821 printf("Echo request timed out\n");
822 else
823 printf("Received echo response.\n");
jjako52c24142002-12-16 13:33:51 +0000824 return 0;
825}
826
827int conf(int type, int cause, struct pdp_t* pdp, void *aid) {
828 /* if (cause < 0) return 0; Some error occurred. We don't care */
829 switch (type) {
830 case GTP_ECHO_REQ:
831 return echo_conf(pdp, cause);
832 case GTP_CREATE_PDP_REQ:
833 if (cause !=128) return 0; /* Request not accepted. We don't care */
834 return create_pdp_conf(pdp, cause);
835 case GTP_DELETE_PDP_REQ:
836 if (cause !=128) return 0; /* Request not accepted. We don't care */
837 return delete_pdp_conf(pdp, cause);
838 default:
839 return 0;
840 }
841}
842
jjako52c24142002-12-16 13:33:51 +0000843
844int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
845 /* printf("encaps_tun. Packet received: forwarding to tun\n");*/
846 return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
847}
848
849int main(int argc, char **argv)
850{
jjako52c24142002-12-16 13:33:51 +0000851 fd_set fds; /* For select() */
852 struct timeval idleTime; /* How long to select() */
jjakoa7cd2492003-04-11 09:40:12 +0000853 struct pdp_t *pdp;
854 int n;
855 int starttime = time(NULL); /* Time program was started */
jjakoafb2a972003-01-29 21:04:13 +0000856
857 struct timezone tz; /* Used for calculating ping times */
858 struct timeval tv;
859 int diff;
jjako52c24142002-12-16 13:33:51 +0000860
jjako52c24142002-12-16 13:33:51 +0000861 /* open a connection to the syslog daemon */
862 /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
863 openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
864
jjakoa7cd2492003-04-11 09:40:12 +0000865 /* Process options given in configuration file and command line */
866 if (process_options(argc, argv))
jjako52c24142002-12-16 13:33:51 +0000867 exit(1);
jjako52c24142002-12-16 13:33:51 +0000868
869 printf("\nInitialising GTP library\n");
jjakoa7cd2492003-04-11 09:40:12 +0000870 if (gtp_new(&gsn, options.statedir, &options.listen)) {
871 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
872 "Failed to create gtp");
873 exit(1);
874 }
875 if (gsn->fd > maxfd) maxfd = gsn->fd;
jjako52c24142002-12-16 13:33:51 +0000876
jjakoa7cd2492003-04-11 09:40:12 +0000877 gtp_set_cb_delete_context(gsn, delete_context);
878 gtp_set_cb_conf(gsn, conf);
879 if (options.createif)
jjako5da68452003-01-28 16:08:47 +0000880 gtp_set_cb_gpdu(gsn, encaps_tun);
881 else
882 gtp_set_cb_gpdu(gsn, encaps_ping);
jjakoa7cd2492003-04-11 09:40:12 +0000883
884 if (options.createif) {
885 printf("Setting up interface\n");
886 /* Create a tunnel interface */
887 if (tun_new((struct tun_t**) &tun)) {
888 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
889 "Failed to create tun");
890 exit(1);
891 }
892 tun_set_cb_ind(tun, cb_tun_ind);
893 if (tun->fd > maxfd) maxfd = tun->fd;
894 }
895
896 /* Initialise hash tables */
897 memset(&iphash, 0, sizeof(iphash));
898 memset(&iparr, 0, sizeof(iparr));
899
jjako52c24142002-12-16 13:33:51 +0000900 printf("Done initialising GTP library\n\n");
jjako52c24142002-12-16 13:33:51 +0000901
902 /* See if anybody is there */
903 printf("Sending off echo request\n");
jjakoa7cd2492003-04-11 09:40:12 +0000904 gtp_echo_req(gsn, &options.remote); /* See if remote is alive ? */
jjako52c24142002-12-16 13:33:51 +0000905
jjakoa7cd2492003-04-11 09:40:12 +0000906 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +0000907 printf("Setting up PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +0000908 iparr[n].inuse = 1; /* TODO */
jjako52c24142002-12-16 13:33:51 +0000909
jjakoa7cd2492003-04-11 09:40:12 +0000910 /* Allocated here. Cleaned up in gtp.c:*/
911 pdp_newpdp(&pdp, options.imsi, n, NULL);
912
913 pdp->peer = &iparr[n];
914 pdp->ipif = tun; /* TODO */
915 iparr[n].pdp = pdp;
916
917 if (options.qos.l > sizeof(pdp->qos_req0)) {
918 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
jjako52c24142002-12-16 13:33:51 +0000919 exit(1);
920 }
921 else {
jjakoa7cd2492003-04-11 09:40:12 +0000922 memcpy(pdp->qos_req0, options.qos.v, options.qos.l);
jjako52c24142002-12-16 13:33:51 +0000923 }
924
jjakoa7cd2492003-04-11 09:40:12 +0000925 pdp->selmode = 0x01; /* MS provided APN, subscription not verified */
jjako52c24142002-12-16 13:33:51 +0000926
jjakoa7cd2492003-04-11 09:40:12 +0000927 if (options.apn.l > sizeof(pdp->apn_use.v)) {
928 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
jjako52c24142002-12-16 13:33:51 +0000929 exit(1);
930 }
931 else {
jjakoa7cd2492003-04-11 09:40:12 +0000932 pdp->apn_use.l = options.apn.l;
933 memcpy(pdp->apn_use.v, options.apn.v, options.apn.l);
jjako52c24142002-12-16 13:33:51 +0000934 }
935
jjakoa7cd2492003-04-11 09:40:12 +0000936 pdp->gsnlc.l = sizeof(options.listen);
937 memcpy(pdp->gsnlc.v, &options.listen, sizeof(options.listen));
938 pdp->gsnlu.l = sizeof(options.listen);
939 memcpy(pdp->gsnlu.v, &options.listen, sizeof(options.listen));
jjako52c24142002-12-16 13:33:51 +0000940
jjakoa7cd2492003-04-11 09:40:12 +0000941 if (options.msisdn.l > sizeof(pdp->msisdn.v)) {
942 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
jjako52c24142002-12-16 13:33:51 +0000943 exit(1);
944 }
945 else {
jjakoa7cd2492003-04-11 09:40:12 +0000946 pdp->msisdn.l = options.msisdn.l;
947 memcpy(pdp->msisdn.v, options.msisdn.v, options.msisdn.l);
948 }
949
950 ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
951
952 if (options.pco.l > sizeof(pdp->pco_req.v)) {
953 sys_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
954 exit(1);
955 }
956 else {
957 pdp->pco_req.l = options.pco.l;
958 memcpy(pdp->pco_req.v, options.pco.v, options.pco.l);
jjako52c24142002-12-16 13:33:51 +0000959 }
960
961 /* Create context */
962 /* We send this of once. Retransmissions are handled by gtplib */
jjakoa7cd2492003-04-11 09:40:12 +0000963 gtp_create_context(gsn, pdp, NULL, &options.remote);
jjako52c24142002-12-16 13:33:51 +0000964 }
965
966 state = 1; /* Enter wait_connection state */
967
968 printf("Waiting for response from ggsn........\n\n");
969
jjako5da68452003-01-28 16:08:47 +0000970
jjako52c24142002-12-16 13:33:51 +0000971 /******************************************************************/
972 /* Main select loop */
973 /******************************************************************/
974
jjakoa7cd2492003-04-11 09:40:12 +0000975 while ((((starttime + options.timelimit + 10) > time(NULL))
976 || (0 == options.timelimit)) && (state!=0)) {
jjako52c24142002-12-16 13:33:51 +0000977
978 /* Take down client connections at some stage */
jjakoa7cd2492003-04-11 09:40:12 +0000979 if (((starttime + options.timelimit) <= time(NULL)) &&
980 (0 != options.timelimit) && (2 == state)) {
jjako52c24142002-12-16 13:33:51 +0000981 state = 3;
jjakoa7cd2492003-04-11 09:40:12 +0000982 for(n=0; n<options.contexts; n++) {
jjako52c24142002-12-16 13:33:51 +0000983 /* Delete context */
984 printf("Disconnecting PDP context #%d\n", n);
jjakoa7cd2492003-04-11 09:40:12 +0000985 gtp_delete_context(gsn, iparr[n].pdp, NULL);
986 if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish();
jjako52c24142002-12-16 13:33:51 +0000987 }
jjakoafb2a972003-01-29 21:04:13 +0000988 }
jjakoa7cd2492003-04-11 09:40:12 +0000989
990 diff = 0;
991 while (( diff<=0 ) &&
jjakoafb2a972003-01-29 21:04:13 +0000992 /* Send off an ICMP ping packet */
jjakoa7cd2492003-04-11 09:40:12 +0000993 /*if (*/(options.pinghost.s_addr) && (2 == state) &&
994 ((pingseq < options.pingcount) || (options.pingcount == 0))) {
jjakoafb2a972003-01-29 21:04:13 +0000995 if (!pingseq) gettimeofday(&firstping, &tz); /* Set time of first ping */
996 gettimeofday(&tv, &tz);
jjakoa7cd2492003-04-11 09:40:12 +0000997 diff = 1000000 / options.pingrate * pingseq -
jjakoafb2a972003-01-29 21:04:13 +0000998 1000000 * (tv.tv_sec - firstping.tv_sec) -
999 (tv.tv_usec - firstping.tv_usec); /* Microseconds safe up to 500 sec */
1000 if (diff <=0) {
jjakoa7cd2492003-04-11 09:40:12 +00001001 if (options.debug) printf("Create_ping %d\n", diff);
1002 create_ping(gsn, iparr[pingseq % options.contexts].pdp,
1003 &options.pinghost, pingseq, options.pingsize);
jjakoafb2a972003-01-29 21:04:13 +00001004 pingseq++;
1005 }
jjako52c24142002-12-16 13:33:51 +00001006 }
jjakoa7cd2492003-04-11 09:40:12 +00001007
jjako52c24142002-12-16 13:33:51 +00001008
jjakoa7cd2492003-04-11 09:40:12 +00001009 if (ntransmitted && options.pingcount && nreceived >= options.pingcount)
jjako5da68452003-01-28 16:08:47 +00001010 ping_finish();
jjakoa7cd2492003-04-11 09:40:12 +00001011
jjako5da68452003-01-28 16:08:47 +00001012
jjako52c24142002-12-16 13:33:51 +00001013 FD_ZERO(&fds);
jjakoa7cd2492003-04-11 09:40:12 +00001014 if (tun) FD_SET(tun->fd, &fds);
1015 FD_SET(gsn->fd, &fds);
jjako52c24142002-12-16 13:33:51 +00001016
1017 gtp_retranstimeout(gsn, &idleTime);
jjakoafb2a972003-01-29 21:04:13 +00001018 ping_timeout(&idleTime);
jjakoa7cd2492003-04-11 09:40:12 +00001019
1020 if (options.debug) printf("idletime.tv_sec %d, idleTime.tv_usec %d\n",
1021 (int) idleTime.tv_sec, (int) idleTime.tv_usec);
1022
jjako52c24142002-12-16 13:33:51 +00001023 switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
1024 case -1:
jjakoa7cd2492003-04-11 09:40:12 +00001025 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1026 "Select returned -1");
jjako52c24142002-12-16 13:33:51 +00001027 break;
1028 case 0:
1029 gtp_retrans(gsn); /* Only retransmit if nothing else */
1030 break;
1031 default:
1032 break;
1033 }
jjakoa7cd2492003-04-11 09:40:12 +00001034
1035 if ((tun) && FD_ISSET(tun->fd, &fds) && tun_decaps(tun) < 0) {
1036 sys_err(LOG_ERR, __FILE__, __LINE__, 0,
1037 "TUN decaps failed");
jjako52c24142002-12-16 13:33:51 +00001038 }
1039
jjakoa7cd2492003-04-11 09:40:12 +00001040 if (FD_ISSET(gsn->fd, &fds))
1041 gtp_decaps(gsn);
jjako52c24142002-12-16 13:33:51 +00001042
jjako5da68452003-01-28 16:08:47 +00001043 }
jjakoa7cd2492003-04-11 09:40:12 +00001044
jjako52c24142002-12-16 13:33:51 +00001045 gtp_free(gsn); /* Clean up the gsn instance */
1046
jjakoa7cd2492003-04-11 09:40:12 +00001047 if (options.createif)
1048 tun_free(tun);
jjako52c24142002-12-16 13:33:51 +00001049
jjakoa7cd2492003-04-11 09:40:12 +00001050 return 0;
jjako52c24142002-12-16 13:33:51 +00001051}
1052